summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2011-04-19 16:35:37 -0500
committerDave Parks <davep@lindenlab.com>2011-04-19 16:35:37 -0500
commit5cf5e4bb888e67dc1dd79eaec491b242a7f3a903 (patch)
tree7b43bff3ea4e1309c6ae4b9bd1fd8ada251f7a52 /indra
parent25566075980d45c30ee25603d94454e081119210 (diff)
parent3b5d6eed12d928e5a7a0bc3a8d827f676b25d060 (diff)
merge
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/lleventdispatcher.cpp566
-rw-r--r--indra/llcommon/lleventdispatcher.h393
-rw-r--r--indra/llcommon/llevents.cpp13
-rw-r--r--indra/llcommon/llevents.h14
-rw-r--r--indra/llcommon/llinstancetracker.cpp17
-rw-r--r--indra/llcommon/llinstancetracker.h30
-rw-r--r--indra/llcommon/llsdutil.cpp27
-rw-r--r--indra/llcommon/llsdutil.h285
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/llcommon/tests/lleventdispatcher_test.cpp1324
-rw-r--r--indra/llimage/llimagedimensionsinfo.cpp83
-rw-r--r--indra/llimage/llimagedimensionsinfo.h3
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp18
-rw-r--r--indra/llplugin/llpluginclassmedia.h9
-rw-r--r--indra/llplugin/llpluginclassmediaowner.h3
-rw-r--r--indra/llrender/llgl.cpp86
-rw-r--r--indra/llrender/llgl.h2
-rw-r--r--indra/llrender/llimagegl.cpp8
-rw-r--r--indra/llui/llfloaterreglistener.cpp17
-rw-r--r--indra/llui/llfloaterreglistener.h1
-rw-r--r--indra/llui/lliconctrl.h1
-rw-r--r--indra/llui/lllineeditor.cpp5
-rw-r--r--indra/llui/lllineeditor.h1
-rw-r--r--indra/llui/llmenugl.cpp3
-rw-r--r--indra/llui/lltextbase.cpp103
-rw-r--r--indra/llui/lltextbase.h4
-rw-r--r--indra/llui/llui.cpp49
-rw-r--r--indra/llui/llui.h27
-rw-r--r--indra/llwindow/CMakeLists.txt4
-rw-r--r--indra/llwindow/llkeyboardheadless.cpp50
-rw-r--r--indra/llwindow/llkeyboardheadless.h45
-rw-r--r--indra/llwindow/llwindow.cpp15
-rw-r--r--indra/llwindow/llwindow.h2
-rw-r--r--indra/llwindow/llwindowheadless.cpp4
-rw-r--r--indra/llwindow/llwindowlistener.cpp307
-rw-r--r--indra/llwindow/llwindowlistener.h55
-rw-r--r--indra/llwindow/llwindowwin32.cpp9
-rw-r--r--indra/media_plugins/webkit/media_plugin_webkit.cpp14
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/CA.pem6471
-rwxr-xr-xindra/newview/app_settings/settings.xml26237
-rw-r--r--indra/newview/app_settings/settings_minimal.xml6
-rw-r--r--indra/newview/character/avatar_lad.xml20
-rwxr-xr-xindra/newview/llagent.cpp11
-rw-r--r--indra/newview/llagentcamera.cpp29
-rw-r--r--indra/newview/llagentlistener.cpp40
-rw-r--r--indra/newview/llagentlistener.h2
-rwxr-xr-xindra/newview/llappviewer.cpp160
-rw-r--r--indra/newview/llappviewer.h1
-rw-r--r--indra/newview/llappviewerlinux.cpp2
-rw-r--r--indra/newview/llappviewermacosx.cpp2
-rw-r--r--indra/newview/llavataractions.cpp41
-rw-r--r--indra/newview/llavatarpropertiesprocessor.cpp25
-rw-r--r--indra/newview/llbreastmotion.cpp36
-rw-r--r--indra/newview/llbreastmotion.h36
-rw-r--r--indra/newview/llcommanddispatcherlistener.cpp2
-rw-r--r--indra/newview/llcommandhandler.cpp17
-rw-r--r--indra/newview/llcommandhandler.h1
-rw-r--r--indra/newview/llexpandabletextbox.cpp33
-rw-r--r--indra/newview/llexpandabletextbox.h6
-rw-r--r--indra/newview/llfirstuse.cpp6
-rw-r--r--indra/newview/llfloaterbump.cpp2
-rw-r--r--indra/newview/llfloaterhelpbrowser.cpp1
-rw-r--r--indra/newview/llfloaterpreference.cpp53
-rw-r--r--indra/newview/llfloaterpreference.h1
-rw-r--r--indra/newview/llhints.cpp20
-rw-r--r--indra/newview/llhudeffectlookat.cpp5
-rw-r--r--indra/newview/llhudmanager.cpp7
-rw-r--r--indra/newview/llimfloater.cpp7
-rw-r--r--indra/newview/llimview.cpp9
-rw-r--r--indra/newview/llinventorybridge.cpp2
-rw-r--r--indra/newview/llinventorymodel.cpp19
-rw-r--r--indra/newview/llinventorymodel.h5
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp6
-rw-r--r--indra/newview/llinventoryobserver.cpp11
-rw-r--r--indra/newview/llinventoryobserver.h1
-rw-r--r--indra/newview/lllogininstance.cpp16
-rw-r--r--indra/newview/llmediactrl.cpp57
-rw-r--r--indra/newview/llmediactrl.h11
-rw-r--r--indra/newview/llnavigationbar.cpp3
-rw-r--r--indra/newview/llpaneleditwearable.cpp6
-rw-r--r--indra/newview/llpanellogin.cpp21
-rw-r--r--indra/newview/llpanellogin.h4
-rw-r--r--indra/newview/llpanelme.cpp24
-rw-r--r--indra/newview/llpanelme.h1
-rw-r--r--indra/newview/llphysicsmotion.cpp1418
-rw-r--r--indra/newview/llphysicsmotion.h242
-rw-r--r--indra/newview/llpolymorph.cpp10
-rw-r--r--indra/newview/llselectmgr.cpp18
-rw-r--r--indra/newview/llsidetray.cpp11
-rw-r--r--indra/newview/llsidetray.h10
-rw-r--r--indra/newview/llsidetraylistener.cpp162
-rw-r--r--indra/newview/llsidetraylistener.h36
-rwxr-xr-xindra/newview/llstartup.cpp138
-rw-r--r--indra/newview/llsurface.cpp5
-rw-r--r--indra/newview/llsyswellwindow.cpp2
-rw-r--r--indra/newview/lltexturestats.cpp2
-rw-r--r--indra/newview/lltoastalertpanel.cpp5
-rw-r--r--indra/newview/lltooldraganddrop.cpp4
-rw-r--r--indra/newview/lltoolpie.cpp232
-rw-r--r--indra/newview/lluilistener.cpp28
-rw-r--r--indra/newview/lluilistener.h1
-rw-r--r--indra/newview/llurldispatcher.cpp25
-rw-r--r--indra/newview/llurldispatcher.h3
-rw-r--r--indra/newview/llurldispatcherlistener.cpp2
-rw-r--r--indra/newview/llviewerdisplay.cpp3014
-rw-r--r--indra/newview/llviewermedia.cpp21
-rw-r--r--indra/newview/llviewermediafocus.cpp12
-rwxr-xr-xindra/newview/llviewermenu.cpp66
-rw-r--r--indra/newview/llviewermessage.cpp23
-rw-r--r--indra/newview/llviewerobject.cpp11
-rw-r--r--indra/newview/llviewerobjectlist.cpp26
-rw-r--r--indra/newview/llviewerparcelmedia.cpp6
-rw-r--r--indra/newview/llviewerparcelmgr.cpp5
-rw-r--r--indra/newview/llviewerregion.cpp37
-rw-r--r--indra/newview/llviewerstats.cpp2
-rwxr-xr-xindra/newview/llviewertexture.cpp108
-rw-r--r--indra/newview/llviewertexturelist.cpp15
-rw-r--r--indra/newview/llviewerwindow.cpp70
-rw-r--r--indra/newview/llviewerwindowlistener.cpp5
-rw-r--r--indra/newview/llvoavatar.cpp16883
-rw-r--r--indra/newview/llvoavatarself.cpp4
-rw-r--r--indra/newview/llwaterparammanager.cpp33
-rw-r--r--indra/newview/llwaterparammanager.h6
-rw-r--r--indra/newview/llwearabletype.cpp2
-rw-r--r--indra/newview/llworld.cpp2681
-rw-r--r--indra/newview/llworldmapview.cpp2
-rwxr-xr-xindra/newview/pipeline.cpp19576
-rw-r--r--indra/newview/skins/default/colors.xml3
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/da/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/de/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences.xml4
-rw-r--r--indra/newview/skins/default/xui/en/menu_media_ctrl.xml31
-rw-r--r--indra/newview/skins/default/xui/en/menu_text_editor.xml15
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml19
-rw-r--r--indra/newview/skins/default/xui/en/panel_hint.xml6
-rw-r--r--indra/newview/skins/default/xui/en/panel_hint_image.xml40
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml1
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_alerts.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_chat.xml20
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_general.xml21
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_move.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_privacy.xml4
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_sound.xml16
-rw-r--r--indra/newview/skins/default/xui/en/panel_profile.xml17
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/es/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/fr/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/it/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/ja/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/nl/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/pl/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_chat.xml3
-rw-r--r--indra/newview/skins/default/xui/pt/panel_preferences_sound.xml3
-rw-r--r--indra/newview/skins/minimal/textures/click_to_move.pngbin0 -> 8188 bytes
-rw-r--r--indra/newview/skins/minimal/textures/textures.xml1
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_bottomtray.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_favorites.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_group_plus.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inventory.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inventory_add.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_mini_map.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_navbar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_object_icon.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_groups.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_place_add_button.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_slurl.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_topinfobar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_bottomtray.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_login.xml1
-rw-r--r--indra/test_apps/llplugintest/llmediaplugintest.cpp10
186 files changed, 42685 insertions, 39671 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 6439ac3349..22e0705036 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -63,6 +63,7 @@ set(llcommon_SOURCE_FILES
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
+ llinstancetracker.cpp
llliveappconfig.cpp
lllivefile.cpp
lllog.cpp
@@ -314,6 +315,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
# *TODO - reenable these once tcmalloc libs no longer break the build.
#ADD_BUILD_TEST(llallocator llcommon)
diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp
index d6e820d793..5b6d4efbe9 100644
--- a/indra/llcommon/lleventdispatcher.cpp
+++ b/indra/llcommon/lleventdispatcher.cpp
@@ -41,6 +41,354 @@
#include "llevents.h"
#include "llerror.h"
#include "llsdutil.h"
+#include "stringize.h"
+#include <memory> // std::auto_ptr
+
+/*****************************************************************************
+* LLSDArgsSource
+*****************************************************************************/
+/**
+ * Store an LLSD array, producing its elements one at a time. Die with LL_ERRS
+ * if the consumer requests more elements than the array contains.
+ */
+class LL_COMMON_API LLSDArgsSource
+{
+public:
+ LLSDArgsSource(const std::string function, const LLSD& args);
+ ~LLSDArgsSource();
+
+ LLSD next();
+
+ void done() const;
+
+private:
+ std::string _function;
+ LLSD _args;
+ LLSD::Integer _index;
+};
+
+LLSDArgsSource::LLSDArgsSource(const std::string function, const LLSD& args):
+ _function(function),
+ _args(args),
+ _index(0)
+{
+ if (! (_args.isUndefined() || _args.isArray()))
+ {
+ LL_ERRS("LLSDArgsSource") << _function << " needs an args array instead of "
+ << _args << LL_ENDL;
+ }
+}
+
+LLSDArgsSource::~LLSDArgsSource()
+{
+ done();
+}
+
+LLSD LLSDArgsSource::next()
+{
+ if (_index >= _args.size())
+ {
+ LL_ERRS("LLSDArgsSource") << _function << " requires more arguments than the "
+ << _args.size() << " provided: " << _args << LL_ENDL;
+ }
+ return _args[_index++];
+}
+
+void LLSDArgsSource::done() const
+{
+ if (_index < _args.size())
+ {
+ LL_WARNS("LLSDArgsSource") << _function << " only consumed " << _index
+ << " of the " << _args.size() << " arguments provided: "
+ << _args << LL_ENDL;
+ }
+}
+
+/*****************************************************************************
+* LLSDArgsMapper
+*****************************************************************************/
+/**
+ * From a formal parameters description and a map of arguments, construct an
+ * arguments array.
+ *
+ * That is, given:
+ * - an LLSD array of length n containing parameter-name strings,
+ * corresponding to the arguments of a function of interest
+ * - an LLSD collection specifying default parameter values, either:
+ * - an LLSD array of length m <= n, matching the rightmost m params, or
+ * - an LLSD map explicitly stating default name=value pairs
+ * - an LLSD map of parameter names and actual values for a particular
+ * function call
+ * construct an LLSD array of actual argument values for this function call.
+ *
+ * The parameter-names array and the defaults collection describe the function
+ * being called. The map might vary with every call, providing argument values
+ * for the described parameters.
+ *
+ * The array of parameter names must match the number of parameters expected
+ * by the function of interest.
+ *
+ * If you pass a map of default parameter values, it provides default values
+ * as you might expect. It is an error to specify a default value for a name
+ * not listed in the parameters array.
+ *
+ * If you pass an array of default parameter values, it is mapped to the
+ * rightmost m of the n parameter names. It is an error if the default-values
+ * array is longer than the parameter-names array. Consider the following
+ * parameter names: ["a", "b", "c", "d"].
+ *
+ * - An empty array of default values (or an isUndefined() value) asserts that
+ * every one of the above parameter names is required.
+ * - An array of four default values [1, 2, 3, 4] asserts that every one of
+ * the above parameters is optional. If the current parameter map is empty,
+ * they will be passed to the function as [1, 2, 3, 4].
+ * - An array of two default values [11, 12] asserts that parameters "a" and
+ * "b" are required, while "c" and "d" are optional, having default values
+ * "c"=11 and "d"=12.
+ *
+ * The arguments array is constructed as follows:
+ *
+ * - Arguments-map keys not found in the parameter-names array are ignored.
+ * - Entries from the map provide values for an improper subset of the
+ * parameters named in the parameter-names array. This results in a
+ * tentative values array with "holes." (size of map) + (number of holes) =
+ * (size of names array)
+ * - Holes are filled with the default values.
+ * - Any remaining holes constitute an error.
+ */
+class LL_COMMON_API LLSDArgsMapper
+{
+public:
+ /// Accept description of function: function name, param names, param
+ /// default values
+ LLSDArgsMapper(const std::string& function, const LLSD& names, const LLSD& defaults);
+
+ /// Given arguments map, return LLSD::Array of parameter values, or LL_ERRS.
+ LLSD map(const LLSD& argsmap) const;
+
+private:
+ static std::string formatlist(const LLSD&);
+
+ // The function-name string is purely descriptive. We want error messages
+ // to be able to indicate which function's LLSDArgsMapper has the problem.
+ std::string _function;
+ // Store the names array pretty much as given.
+ LLSD _names;
+ // Though we're handed an array of name strings, it's more useful to us to
+ // store it as a map from name string to position index. Of course that's
+ // easy to generate from the incoming names array, but why do it more than
+ // once?
+ typedef std::map<LLSD::String, LLSD::Integer> IndexMap;
+ IndexMap _indexes;
+ // Generated array of default values, aligned with the array of param names.
+ LLSD _defaults;
+ // Indicate whether we have a default value for each param.
+ typedef std::vector<char> FilledVector;
+ FilledVector _has_dft;
+};
+
+LLSDArgsMapper::LLSDArgsMapper(const std::string& function,
+ const LLSD& names, const LLSD& defaults):
+ _function(function),
+ _names(names),
+ _has_dft(names.size())
+{
+ if (! (_names.isUndefined() || _names.isArray()))
+ {
+ LL_ERRS("LLSDArgsMapper") << function << " names must be an array, not " << names << LL_ENDL;
+ }
+ LLSD::Integer nparams(_names.size());
+ // From _names generate _indexes.
+ for (LLSD::Integer ni = 0, nend = _names.size(); ni < nend; ++ni)
+ {
+ _indexes[_names[ni]] = ni;
+ }
+
+ // Presize _defaults() array so we don't have to resize it more than once.
+ // All entries are initialized to LLSD(); but since _has_dft is still all
+ // 0, they're all "holes" for now.
+ if (nparams)
+ {
+ _defaults[nparams - 1] = LLSD();
+ }
+
+ if (defaults.isUndefined() || defaults.isArray())
+ {
+ LLSD::Integer ndefaults = defaults.size();
+ // defaults is a (possibly empty) array. Right-align it with names.
+ if (ndefaults > nparams)
+ {
+ LL_ERRS("LLSDArgsMapper") << function << " names array " << names
+ << " shorter than defaults array " << defaults << LL_ENDL;
+ }
+
+ // Offset by which we slide defaults array right to right-align with
+ // _names array
+ LLSD::Integer offset = nparams - ndefaults;
+ // Fill rightmost _defaults entries from defaults, and mark them as
+ // filled
+ for (LLSD::Integer i = 0, iend = ndefaults; i < iend; ++i)
+ {
+ _defaults[i + offset] = defaults[i];
+ _has_dft[i + offset] = 1;
+ }
+ }
+ else if (defaults.isMap())
+ {
+ // defaults is a map. Use it to populate the _defaults array.
+ LLSD bogus;
+ for (LLSD::map_const_iterator mi(defaults.beginMap()), mend(defaults.endMap());
+ mi != mend; ++mi)
+ {
+ IndexMap::const_iterator ixit(_indexes.find(mi->first));
+ if (ixit == _indexes.end())
+ {
+ bogus.append(mi->first);
+ continue;
+ }
+
+ LLSD::Integer pos = ixit->second;
+ // Store default value at that position in the _defaults array.
+ _defaults[pos] = mi->second;
+ // Don't forget to record the fact that we've filled this
+ // position.
+ _has_dft[pos] = 1;
+ }
+ if (bogus.size())
+ {
+ LL_ERRS("LLSDArgsMapper") << function << " defaults specified for nonexistent params "
+ << formatlist(bogus) << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_ERRS("LLSDArgsMapper") << function << " defaults must be a map or an array, not "
+ << defaults << LL_ENDL;
+ }
+}
+
+LLSD LLSDArgsMapper::map(const LLSD& argsmap) const
+{
+ if (! (argsmap.isUndefined() || argsmap.isMap() || argsmap.isArray()))
+ {
+ LL_ERRS("LLSDArgsMapper") << _function << " map() needs a map or array, not "
+ << argsmap << LL_ENDL;
+ }
+ // Initialize the args array. Indexing a non-const LLSD array grows it
+ // to appropriate size, but we don't want to resize this one on each
+ // new operation. Just make it as big as we need before we start
+ // stuffing values into it.
+ LLSD args(LLSD::emptyArray());
+ if (_defaults.size() == 0)
+ {
+ // If this function requires no arguments, fast exit. (Don't try to
+ // assign to args[-1].)
+ return args;
+ }
+ args[_defaults.size() - 1] = LLSD();
+
+ // Get a vector of chars to indicate holes. It's tempting to just scan
+ // for LLSD::isUndefined() values after filling the args array from
+ // the map, but it's plausible for caller to explicitly pass
+ // isUndefined() as the value of some parameter name. That's legal
+ // since isUndefined() has well-defined conversions (default value)
+ // for LLSD data types. So use a whole separate array for detecting
+ // holes. (Avoid std::vector<bool> which is known to be odd -- can we
+ // iterate?)
+ FilledVector filled(args.size());
+
+ if (argsmap.isArray())
+ {
+ // Fill args from array. If there are too many args in passed array,
+ // ignore the rest.
+ LLSD::Integer size(argsmap.size());
+ if (size > args.size())
+ {
+ // We don't just use std::min() because we want to sneak in this
+ // warning if caller passes too many args.
+ LL_WARNS("LLSDArgsMapper") << _function << " needs " << args.size()
+ << " params, ignoring last " << (size - args.size())
+ << " of passed " << size << ": " << argsmap << LL_ENDL;
+ size = args.size();
+ }
+ for (LLSD::Integer i(0); i < size; ++i)
+ {
+ // Copy the actual argument from argsmap
+ args[i] = argsmap[i];
+ // Note that it's been filled
+ filled[i] = 1;
+ }
+ }
+ else
+ {
+ // argsmap is in fact a map. Walk the map.
+ for (LLSD::map_const_iterator mi(argsmap.beginMap()), mend(argsmap.endMap());
+ mi != mend; ++mi)
+ {
+ // mi->first is a parameter-name string, with mi->second its
+ // value. Look up the name's position index in _indexes.
+ IndexMap::const_iterator ixit(_indexes.find(mi->first));
+ if (ixit == _indexes.end())
+ {
+ // Allow for a map containing more params than were passed in
+ // our names array. Caller typically receives a map containing
+ // the function name, cruft such as reqid, etc. Ignore keys
+ // not defined in _indexes.
+ LL_DEBUGS("LLSDArgsMapper") << _function << " ignoring "
+ << mi->first << "=" << mi->second << LL_ENDL;
+ continue;
+ }
+ LLSD::Integer pos = ixit->second;
+ // Store the value at that position in the args array.
+ args[pos] = mi->second;
+ // Don't forget to record the fact that we've filled this
+ // position.
+ filled[pos] = 1;
+ }
+ }
+
+ // Fill any remaining holes from _defaults.
+ LLSD unfilled(LLSD::emptyArray());
+ for (LLSD::Integer i = 0, iend = args.size(); i < iend; ++i)
+ {
+ if (! filled[i])
+ {
+ // If there's no default value for this parameter, that's an
+ // error.
+ if (! _has_dft[i])
+ {
+ unfilled.append(_names[i]);
+ }
+ else
+ {
+ args[i] = _defaults[i];
+ }
+ }
+ }
+ // If any required args -- args without defaults -- were left unfilled
+ // by argsmap, that's a problem.
+ if (unfilled.size())
+ {
+ LL_ERRS("LLSDArgsMapper") << _function << " missing required arguments "
+ << formatlist(unfilled) << " from " << argsmap << LL_ENDL;
+ }
+
+ // done
+ return args;
+}
+
+std::string LLSDArgsMapper::formatlist(const LLSD& list)
+{
+ std::ostringstream out;
+ const char* delim = "";
+ for (LLSD::array_const_iterator li(list.beginArray()), lend(list.endArray());
+ li != lend; ++li)
+ {
+ out << delim << li->asString();
+ delim = ", ";
+ }
+ return out.str();
+}
LLEventDispatcher::LLEventDispatcher(const std::string& desc, const std::string& key):
mDesc(desc),
@@ -52,12 +400,181 @@ LLEventDispatcher::~LLEventDispatcher()
{
}
+/**
+ * DispatchEntry subclass used for callables accepting(const LLSD&)
+ */
+struct LLEventDispatcher::LLSDDispatchEntry: public LLEventDispatcher::DispatchEntry
+{
+ LLSDDispatchEntry(const std::string& desc, const Callable& func, const LLSD& required):
+ DispatchEntry(desc),
+ mFunc(func),
+ mRequired(required)
+ {}
+
+ Callable mFunc;
+ LLSD mRequired;
+
+ virtual void call(const std::string& desc, const LLSD& event) const
+ {
+ // Validate the syntax of the event itself.
+ std::string mismatch(llsd_matches(mRequired, event));
+ if (! mismatch.empty())
+ {
+ LL_ERRS("LLEventDispatcher") << desc << ": bad request: " << mismatch << LL_ENDL;
+ }
+ // Event syntax looks good, go for it!
+ mFunc(event);
+ }
+
+ virtual LLSD addMetadata(LLSD meta) const
+ {
+ meta["required"] = mRequired;
+ return meta;
+ }
+};
+
+/**
+ * DispatchEntry subclass for passing LLSD to functions accepting
+ * arbitrary argument types (convertible via LLSDParam)
+ */
+struct LLEventDispatcher::ParamsDispatchEntry: public LLEventDispatcher::DispatchEntry
+{
+ ParamsDispatchEntry(const std::string& desc, const invoker_function& func):
+ DispatchEntry(desc),
+ mInvoker(func)
+ {}
+
+ invoker_function mInvoker;
+
+ virtual void call(const std::string& desc, const LLSD& event) const
+ {
+ LLSDArgsSource src(desc, event);
+ mInvoker(boost::bind(&LLSDArgsSource::next, boost::ref(src)));
+ }
+};
+
+/**
+ * DispatchEntry subclass for dispatching LLSD::Array to functions accepting
+ * arbitrary argument types (convertible via LLSDParam)
+ */
+struct LLEventDispatcher::ArrayParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry
+{
+ ArrayParamsDispatchEntry(const std::string& desc, const invoker_function& func,
+ LLSD::Integer arity):
+ ParamsDispatchEntry(desc, func),
+ mArity(arity)
+ {}
+
+ LLSD::Integer mArity;
+
+ virtual LLSD addMetadata(LLSD meta) const
+ {
+ LLSD array(LLSD::emptyArray());
+ // Resize to number of arguments required
+ if (mArity)
+ array[mArity - 1] = LLSD();
+ llassert_always(array.size() == mArity);
+ meta["required"] = array;
+ return meta;
+ }
+};
+
+/**
+ * DispatchEntry subclass for dispatching LLSD::Map to functions accepting
+ * arbitrary argument types (convertible via LLSDParam)
+ */
+struct LLEventDispatcher::MapParamsDispatchEntry: public LLEventDispatcher::ParamsDispatchEntry
+{
+ MapParamsDispatchEntry(const std::string& name, const std::string& desc,
+ const invoker_function& func,
+ const LLSD& params, const LLSD& defaults):
+ ParamsDispatchEntry(desc, func),
+ mMapper(name, params, defaults),
+ mRequired(LLSD::emptyMap())
+ {
+ // Build the set of all param keys, then delete the ones that are
+ // optional. What's left are the ones that are required.
+ for (LLSD::array_const_iterator pi(params.beginArray()), pend(params.endArray());
+ pi != pend; ++pi)
+ {
+ mRequired[pi->asString()] = LLSD();
+ }
+
+ if (defaults.isArray() || defaults.isUndefined())
+ {
+ // Right-align the params and defaults arrays.
+ LLSD::Integer offset = params.size() - defaults.size();
+ // Now the name of every defaults[i] is at params[i + offset].
+ for (LLSD::Integer i(0), iend(defaults.size()); i < iend; ++i)
+ {
+ // Erase this optional param from mRequired.
+ mRequired.erase(params[i + offset].asString());
+ // Instead, make an entry in mOptional with the default
+ // param's name and value.
+ mOptional[params[i + offset].asString()] = defaults[i];
+ }
+ }
+ else if (defaults.isMap())
+ {
+ // if defaults is already a map, then it's already in the form we
+ // intend to deliver in metadata
+ mOptional = defaults;
+ // Just delete from mRequired every key appearing in mOptional.
+ for (LLSD::map_const_iterator mi(mOptional.beginMap()), mend(mOptional.endMap());
+ mi != mend; ++mi)
+ {
+ mRequired.erase(mi->first);
+ }
+ }
+ }
+
+ LLSDArgsMapper mMapper;
+ LLSD mRequired;
+ LLSD mOptional;
+
+ virtual void call(const std::string& desc, const LLSD& event) const
+ {
+ // Just convert from LLSD::Map to LLSD::Array using mMapper, then pass
+ // to base-class call() method.
+ ParamsDispatchEntry::call(desc, mMapper.map(event));
+ }
+
+ virtual LLSD addMetadata(LLSD meta) const
+ {
+ meta["required"] = mRequired;
+ meta["optional"] = mOptional;
+ return meta;
+ }
+};
+
+void LLEventDispatcher::addArrayParamsDispatchEntry(const std::string& name,
+ const std::string& desc,
+ const invoker_function& invoker,
+ LLSD::Integer arity)
+{
+ mDispatch.insert(
+ DispatchMap::value_type(name, DispatchMap::mapped_type(
+ new ArrayParamsDispatchEntry(desc, invoker, arity))));
+}
+
+void LLEventDispatcher::addMapParamsDispatchEntry(const std::string& name,
+ const std::string& desc,
+ const invoker_function& invoker,
+ const LLSD& params,
+ const LLSD& defaults)
+{
+ mDispatch.insert(
+ DispatchMap::value_type(name, DispatchMap::mapped_type(
+ new MapParamsDispatchEntry(name, desc, invoker, params, defaults))));
+}
+
/// Register a callable by name
void LLEventDispatcher::add(const std::string& name, const std::string& desc,
const Callable& callable, const LLSD& required)
{
- mDispatch.insert(DispatchMap::value_type(name,
- DispatchMap::mapped_type(callable, desc, required)));
+ mDispatch.insert(
+ DispatchMap::value_type(name, DispatchMap::mapped_type(
+ new LLSDDispatchEntry(desc, callable, required))));
}
void LLEventDispatcher::addFail(const std::string& name, const std::string& classname) const
@@ -83,7 +600,7 @@ bool LLEventDispatcher::remove(const std::string& name)
/// such callable exists, die with LL_ERRS.
void LLEventDispatcher::operator()(const std::string& name, const LLSD& event) const
{
- if (! attemptCall(name, event))
+ if (! try_call(name, event))
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): '" << name
<< "' not found" << LL_ENDL;
@@ -98,44 +615,29 @@ void LLEventDispatcher::operator()(const LLSD& event) const
// This could/should be implemented in terms of the two-arg overload.
// However -- we can produce a more informative error message.
std::string name(event[mKey]);
- if (! attemptCall(name, event))
+ if (! try_call(name, event))
{
LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << "): bad " << mKey
<< " value '" << name << "'" << LL_ENDL;
}
}
-bool LLEventDispatcher::attemptCall(const std::string& name, const LLSD& event) const
+bool LLEventDispatcher::try_call(const LLSD& event) const
{
- DispatchMap::const_iterator found = mDispatch.find(name);
- if (found == mDispatch.end())
- {
- // The reason we only return false, leaving it up to our caller to die
- // with LL_ERRS, is that different callers have different amounts of
- // available information.
- return false;
- }
- // Found the name, so it's plausible to even attempt the call. But first,
- // validate the syntax of the event itself.
- std::string mismatch(llsd_matches(found->second.mRequired, event));
- if (! mismatch.empty())
- {
- LL_ERRS("LLEventDispatcher") << "LLEventDispatcher(" << mDesc << ") calling '" << name
- << "': bad request: " << mismatch << LL_ENDL;
- }
- // Event syntax looks good, go for it!
- (found->second.mFunc)(event);
- return true; // tell caller we were able to call
+ return try_call(event[mKey], event);
}
-LLEventDispatcher::Callable LLEventDispatcher::get(const std::string& name) const
+bool LLEventDispatcher::try_call(const std::string& name, const LLSD& event) const
{
DispatchMap::const_iterator found = mDispatch.find(name);
if (found == mDispatch.end())
{
- return Callable();
+ return false;
}
- return found->second.mFunc;
+ // Found the name, so it's plausible to even attempt the call.
+ found->second->call(STRINGIZE("LLEventDispatcher(" << mDesc << ") calling '" << name << "'"),
+ event);
+ return true; // tell caller we were able to call
}
LLSD LLEventDispatcher::getMetadata(const std::string& name) const
@@ -147,9 +649,8 @@ LLSD LLEventDispatcher::getMetadata(const std::string& name) const
}
LLSD meta;
meta["name"] = name;
- meta["desc"] = found->second.mDesc;
- meta["required"] = found->second.mRequired;
- return meta;
+ meta["desc"] = found->second->mDesc;
+ return found->second->addMetadata(meta);
}
LLDispatchListener::LLDispatchListener(const std::string& pumpname, const std::string& key):
@@ -164,3 +665,8 @@ bool LLDispatchListener::process(const LLSD& event)
(*this)(event);
return false;
}
+
+LLEventDispatcher::DispatchEntry::DispatchEntry(const std::string& desc):
+ mDesc(desc)
+{}
+
diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h
index dfffd59eb6..7acc61de4e 100644
--- a/indra/llcommon/lleventdispatcher.h
+++ b/indra/llcommon/lleventdispatcher.h
@@ -27,18 +27,56 @@
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
+ *
+ * The invoker machinery that constructs a boost::fusion argument list for use
+ * with boost::fusion::invoke() is derived from
+ * http://www.boost.org/doc/libs/1_45_0/libs/function_types/example/interpreter.hpp
+ * whose license information is copied below:
+ *
+ * "(C) Copyright Tobias Schwinger
+ *
+ * Use modification and distribution are subject to the boost Software License,
+ * Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)."
*/
#if ! defined(LL_LLEVENTDISPATCHER_H)
#define LL_LLEVENTDISPATCHER_H
+// nil is too generic a term to be allowed to be a global macro. In
+// particular, boost::fusion defines a 'class nil' (properly encapsulated in a
+// namespace) that a global 'nil' macro breaks badly.
+#if defined(nil)
+// Capture the value of the macro 'nil', hoping int is an appropriate type.
+static const int nil_(nil);
+// Now forget the macro.
+#undef nil
+// Finally, reintroduce 'nil' as a properly-scoped alias for the previously-
+// defined const 'nil_'. Make it static since otherwise it produces duplicate-
+// symbol link errors later.
+static const int& nil(nil_);
+#endif
+
#include <string>
-#include <map>
+#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/iterator/transform_iterator.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/function_types/is_nonmember_callable_builtin.hpp>
+#include <boost/function_types/parameter_types.hpp>
+#include <boost/function_types/function_arity.hpp>
+#include <boost/type_traits/remove_cv.hpp>
+#include <boost/type_traits/remove_reference.hpp>
+#include <boost/fusion/include/push_back.hpp>
+#include <boost/fusion/include/cons.hpp>
+#include <boost/fusion/include/invoke.hpp>
+#include <boost/mpl/begin.hpp>
+#include <boost/mpl/end.hpp>
+#include <boost/mpl/next.hpp>
+#include <boost/mpl/deref.hpp>
#include <typeinfo>
#include "llevents.h"
+#include "llsdutil.h"
class LLSD;
@@ -54,12 +92,18 @@ public:
LLEventDispatcher(const std::string& desc, const std::string& key);
virtual ~LLEventDispatcher();
- /// Accept any C++ callable, typically a boost::bind() expression
+ /// @name Register functions accepting(const LLSD&)
+ //@{
+
+ /// Accept any C++ callable with the right signature, typically a
+ /// boost::bind() expression
typedef boost::function<void(const LLSD&)> Callable;
/**
- * Register a @a callable by @a name. The optional @a required parameter
- * is used to validate the structure of each incoming event (see
+ * Register a @a callable by @a name. The passed @a callable accepts a
+ * single LLSD value and uses it in any way desired, e.g. extract
+ * parameters and call some other function. The optional @a required
+ * parameter is used to validate the structure of each incoming event (see
* llsd_matches()).
*/
void add(const std::string& name,
@@ -68,9 +112,23 @@ public:
const LLSD& required=LLSD());
/**
+ * The case of a free function (or static method) accepting(const LLSD&)
+ * could also be intercepted by the arbitrary-args overload below. Ensure
+ * that it's directed to the Callable overload above instead.
+ */
+ void add(const std::string& name,
+ const std::string& desc,
+ void (*f)(const LLSD&),
+ const LLSD& required=LLSD())
+ {
+ add(name, desc, Callable(f), required);
+ }
+
+ /**
* Special case: a subclass of this class can pass an unbound member
- * function pointer without explicitly specifying the
- * <tt>boost::bind()</tt> expression.
+ * function pointer (of an LLEventDispatcher subclass) without explicitly
+ * specifying the <tt>boost::bind()</tt> expression. The passed @a method
+ * accepts a single LLSD value, presumably containing other parameters.
*/
template <class CLASS>
void add(const std::string& name,
@@ -81,7 +139,8 @@ public:
addMethod<CLASS>(name, desc, method, required);
}
- /// Overload for both const and non-const methods
+ /// Overload for both const and non-const methods. The passed @a method
+ /// accepts a single LLSD value, presumably containing other parameters.
template <class CLASS>
void add(const std::string& name,
const std::string& desc,
@@ -91,15 +150,106 @@ public:
addMethod<CLASS>(name, desc, method, required);
}
- /// Convenience: for LLEventDispatcher, not every callable needs a
- /// documentation string.
- template <typename CALLABLE>
- void add(const std::string& name,
- CALLABLE callable,
- const LLSD& required=LLSD())
- {
- add(name, "", callable, required);
- }
+ //@}
+
+ /// @name Register functions with arbitrary param lists
+ //@{
+
+ /**
+ * Register a free function with arbitrary parameters. (This also works
+ * for static class methods.)
+ *
+ * @note This supports functions with up to about 6 parameters -- after
+ * that you start getting dismaying compile errors in which
+ * boost::fusion::joint_view is mentioned a surprising number of times.
+ *
+ * When calling this name, pass an LLSD::Array. Each entry in turn will be
+ * converted to the corresponding parameter type using LLSDParam.
+ */
+ template<typename Function>
+ typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin<Function>
+ >::type add(const std::string& name,
+ const std::string& desc,
+ Function f);
+
+ /**
+ * Register a nonstatic class method with arbitrary parameters.
+ *
+ * @note This supports functions with up to about 6 parameters -- after
+ * that you start getting dismaying compile errors in which
+ * boost::fusion::joint_view is mentioned a surprising number of times.
+ *
+ * To cover cases such as a method on an LLSingleton we don't yet want to
+ * instantiate, instead of directly storing an instance pointer, accept a
+ * nullary callable returning a pointer/reference to the desired class
+ * instance. If you already have an instance in hand,
+ * boost::lambda::var(instance) or boost::lambda::constant(instance_ptr)
+ * produce suitable callables.
+ *
+ * When calling this name, pass an LLSD::Array. Each entry in turn will be
+ * converted to the corresponding parameter type using LLSDParam.
+ */
+ template<typename Method, typename InstanceGetter>
+ typename boost::enable_if< boost::function_types::is_member_function_pointer<Method>
+ >::type add(const std::string& name,
+ const std::string& desc,
+ Method f,
+ const InstanceGetter& getter);
+
+ /**
+ * Register a free function with arbitrary parameters. (This also works
+ * for static class methods.)
+ *
+ * @note This supports functions with up to about 6 parameters -- after
+ * that you start getting dismaying compile errors in which
+ * boost::fusion::joint_view is mentioned a surprising number of times.
+ *
+ * Pass an LLSD::Array of parameter names, and optionally another
+ * LLSD::Array of default parameter values, a la LLSDArgsMapper.
+ *
+ * When calling this name, pass an LLSD::Map. We will internally generate
+ * an LLSD::Array using LLSDArgsMapper and then convert each entry in turn
+ * to the corresponding parameter type using LLSDParam.
+ */
+ template<typename Function>
+ typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin<Function>
+ >::type add(const std::string& name,
+ const std::string& desc,
+ Function f,
+ const LLSD& params,
+ const LLSD& defaults=LLSD());
+
+ /**
+ * Register a nonstatic class method with arbitrary parameters.
+ *
+ * @note This supports functions with up to about 6 parameters -- after
+ * that you start getting dismaying compile errors in which
+ * boost::fusion::joint_view is mentioned a surprising number of times.
+ *
+ * To cover cases such as a method on an LLSingleton we don't yet want to
+ * instantiate, instead of directly storing an instance pointer, accept a
+ * nullary callable returning a pointer/reference to the desired class
+ * instance. If you already have an instance in hand,
+ * boost::lambda::var(instance) or boost::lambda::constant(instance_ptr)
+ * produce suitable callables.
+ *
+ * Pass an LLSD::Array of parameter names, and optionally another
+ * LLSD::Array of default parameter values, a la LLSDArgsMapper.
+ *
+ * When calling this name, pass an LLSD::Map. We will internally generate
+ * an LLSD::Array using LLSDArgsMapper and then convert each entry in turn
+ * to the corresponding parameter type using LLSDParam.
+ */
+ template<typename Method, typename InstanceGetter>
+ typename boost::enable_if< boost::function_types::is_member_function_pointer<Method>
+ >::type add(const std::string& name,
+ const std::string& desc,
+ Method f,
+ const InstanceGetter& getter,
+ const LLSD& params,
+ const LLSD& defaults=LLSD());
+
+ //@}
/// Unregister a callable
bool remove(const std::string& name);
@@ -109,12 +259,25 @@ public:
/// the @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const std::string& name, const LLSD& event) const;
+ /// Call a registered callable with an explicitly-specified name and
+ /// return <tt>true</tt>. If no such callable exists, return
+ /// <tt>false</tt>. If the @a event fails to match the @a required
+ /// prototype specified at add() time, die with LL_ERRS.
+ bool try_call(const std::string& name, const LLSD& event) const;
+
/// Extract the @a key value from the incoming @a event, and call the
/// callable whose name is specified by that map @a key. If no such
/// callable exists, die with LL_ERRS. If the @a event fails to match the
/// @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const LLSD& event) const;
+ /// Extract the @a key value from the incoming @a event, call the callable
+ /// whose name is specified by that map @a key and return <tt>true</tt>.
+ /// If no such callable exists, return <tt>false</tt>. If the @a event
+ /// fails to match the @a required prototype specified at add() time, die
+ /// with LL_ERRS.
+ bool try_call(const LLSD& event) const;
+
/// @name Iterate over defined names
//@{
typedef std::pair<std::string, std::string> NameDesc;
@@ -122,16 +285,22 @@ public:
private:
struct DispatchEntry
{
- DispatchEntry(const Callable& func, const std::string& desc, const LLSD& required):
- mFunc(func),
- mDesc(desc),
- mRequired(required)
- {}
- Callable mFunc;
+ DispatchEntry(const std::string& desc);
+ virtual ~DispatchEntry() {} // suppress MSVC warning, sigh
+
std::string mDesc;
- LLSD mRequired;
+
+ virtual void call(const std::string& desc, const LLSD& event) const = 0;
+ virtual LLSD addMetadata(LLSD) const = 0;
};
- typedef std::map<std::string, DispatchEntry> DispatchMap;
+ // Tried using boost::ptr_map<std::string, DispatchEntry>, but ptr_map<>
+ // wants its value type to be "clonable," even just to dereference an
+ // iterator. I don't want to clone entries -- if I have to copy an entry
+ // around, I want it to continue pointing to the same DispatchEntry
+ // subclass object. However, I definitely want DispatchMap to destroy
+ // DispatchEntry if no references are outstanding at the time an entry is
+ // removed. This looks like a job for boost::shared_ptr.
+ typedef std::map<std::string, boost::shared_ptr<DispatchEntry> > DispatchMap;
public:
/// We want the flexibility to redefine what data we store per name,
@@ -149,10 +318,6 @@ public:
}
//@}
- /// Fetch the Callable for the specified name. If no such name was
- /// registered, return an empty() Callable.
- Callable get(const std::string& name) const;
-
/// Get information about a specific Callable
LLSD getMetadata(const std::string& name) const;
@@ -175,18 +340,184 @@ private:
}
}
void addFail(const std::string& name, const std::string& classname) const;
- /// try to dispatch, return @c true if success
- bool attemptCall(const std::string& name, const LLSD& event) const;
std::string mDesc, mKey;
DispatchMap mDispatch;
static NameDesc makeNameDesc(const DispatchMap::value_type& item)
{
- return NameDesc(item.first, item.second.mDesc);
+ return NameDesc(item.first, item.second->mDesc);
+ }
+
+ struct LLSDDispatchEntry;
+ struct ParamsDispatchEntry;
+ struct ArrayParamsDispatchEntry;
+ struct MapParamsDispatchEntry;
+
+ // Step 2 of parameter analysis. Instantiating invoker<some_function_type>
+ // implicitly sets its From and To parameters to the (compile time) begin
+ // and end iterators over that function's parameter types.
+ template< typename Function
+ , class From = typename boost::mpl::begin< boost::function_types::parameter_types<Function> >::type
+ , class To = typename boost::mpl::end< boost::function_types::parameter_types<Function> >::type
+ >
+ struct invoker;
+
+ // deliver LLSD arguments one at a time
+ typedef boost::function<LLSD()> args_source;
+ // obtain args from an args_source to build param list and call target
+ // function
+ typedef boost::function<void(const args_source&)> invoker_function;
+
+ template <typename Function>
+ invoker_function make_invoker(Function f);
+ template <typename Method, typename InstanceGetter>
+ invoker_function make_invoker(Method f, const InstanceGetter& getter);
+ void addArrayParamsDispatchEntry(const std::string& name,
+ const std::string& desc,
+ const invoker_function& invoker,
+ LLSD::Integer arity);
+ void addMapParamsDispatchEntry(const std::string& name,
+ const std::string& desc,
+ const invoker_function& invoker,
+ const LLSD& params,
+ const LLSD& defaults);
+};
+
+/*****************************************************************************
+* LLEventDispatcher template implementation details
+*****************************************************************************/
+// Step 3 of parameter analysis, the recursive case.
+template<typename Function, class From, class To>
+struct LLEventDispatcher::invoker
+{
+ template<typename T>
+ struct remove_cv_ref
+ : boost::remove_cv< typename boost::remove_reference<T>::type >
+ { };
+
+ // apply() accepts an arbitrary boost::fusion sequence as args. It
+ // examines the next parameter type in the parameter-types sequence
+ // bounded by From and To, obtains the next LLSD object from the passed
+ // args_source and constructs an LLSDParam of appropriate type to try
+ // to convert the value. It then recurs with the next parameter-types
+ // iterator, passing the args sequence thus far.
+ template<typename Args>
+ static inline
+ void apply(Function func, const args_source& argsrc, Args const & args)
+ {
+ typedef typename boost::mpl::deref<From>::type arg_type;
+ typedef typename boost::mpl::next<From>::type next_iter_type;
+ typedef typename remove_cv_ref<arg_type>::type plain_arg_type;
+
+ invoker<Function, next_iter_type, To>::apply
+ ( func, argsrc, boost::fusion::push_back(args, LLSDParam<plain_arg_type>(argsrc())));
+ }
+
+ // Special treatment for instance (first) parameter of a non-static member
+ // function. Accept the instance-getter callable, calling that to produce
+ // the first args value. Since we know we're at the top of the recursion
+ // chain, we need not also require a partial args sequence from our caller.
+ template <typename InstanceGetter>
+ static inline
+ void method_apply(Function func, const args_source& argsrc, const InstanceGetter& getter)
+ {
+ typedef typename boost::mpl::next<From>::type next_iter_type;
+
+ // Instead of grabbing the first item from argsrc and making an
+ // LLSDParam of it, call getter() and pass that as the instance param.
+ invoker<Function, next_iter_type, To>::apply
+ ( func, argsrc, boost::fusion::push_back(boost::fusion::nil(), boost::ref(getter())));
+ }
+};
+
+// Step 4 of parameter analysis, the leaf case. When the general
+// invoker<Function, From, To> logic has advanced From until it matches To,
+// the compiler will pick this template specialization.
+template<typename Function, class To>
+struct LLEventDispatcher::invoker<Function,To,To>
+{
+ // the argument list is complete, now call the function
+ template<typename Args>
+ static inline
+ void apply(Function func, const args_source&, Args const & args)
+ {
+ boost::fusion::invoke(func, args);
}
};
+template<typename Function>
+typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin<Function> >::type
+LLEventDispatcher::add(const std::string& name, const std::string& desc, Function f)
+{
+ // Construct an invoker_function, a callable accepting const args_source&.
+ // Add to DispatchMap an ArrayParamsDispatchEntry that will handle the
+ // caller's LLSD::Array.
+ addArrayParamsDispatchEntry(name, desc, make_invoker(f),
+ boost::function_types::function_arity<Function>::value);
+}
+
+template<typename Method, typename InstanceGetter>
+typename boost::enable_if< boost::function_types::is_member_function_pointer<Method> >::type
+LLEventDispatcher::add(const std::string& name, const std::string& desc, Method f,
+ const InstanceGetter& getter)
+{
+ // Subtract 1 from the compile-time arity because the getter takes care of
+ // the first parameter. We only need (arity - 1) additional arguments.
+ addArrayParamsDispatchEntry(name, desc, make_invoker(f, getter),
+ boost::function_types::function_arity<Method>::value - 1);
+}
+
+template<typename Function>
+typename boost::enable_if< boost::function_types::is_nonmember_callable_builtin<Function> >::type
+LLEventDispatcher::add(const std::string& name, const std::string& desc, Function f,
+ const LLSD& params, const LLSD& defaults)
+{
+ // See comments for previous is_nonmember_callable_builtin add().
+ addMapParamsDispatchEntry(name, desc, make_invoker(f), params, defaults);
+}
+
+template<typename Method, typename InstanceGetter>
+typename boost::enable_if< boost::function_types::is_member_function_pointer<Method> >::type
+LLEventDispatcher::add(const std::string& name, const std::string& desc, Method f,
+ const InstanceGetter& getter,
+ const LLSD& params, const LLSD& defaults)
+{
+ addMapParamsDispatchEntry(name, desc, make_invoker(f, getter), params, defaults);
+}
+
+template <typename Function>
+LLEventDispatcher::invoker_function
+LLEventDispatcher::make_invoker(Function f)
+{
+ // Step 1 of parameter analysis, the top of the recursion. Passing a
+ // suitable f (see add()'s enable_if condition) to this method causes it
+ // to infer the function type; specifying that function type to invoker<>
+ // causes it to fill in the begin/end MPL iterators over the function's
+ // list of parameter types.
+ // While normally invoker::apply() could infer its template type from the
+ // boost::fusion::nil parameter value, here we must be explicit since
+ // we're boost::bind()ing it rather than calling it directly.
+ return boost::bind(&invoker<Function>::template apply<boost::fusion::nil>,
+ f,
+ _1,
+ boost::fusion::nil());
+}
+
+template <typename Method, typename InstanceGetter>
+LLEventDispatcher::invoker_function
+LLEventDispatcher::make_invoker(Method f, const InstanceGetter& getter)
+{
+ // Use invoker::method_apply() to treat the instance (first) arg specially.
+ return boost::bind(&invoker<Method>::template method_apply<InstanceGetter>,
+ f,
+ _1,
+ getter);
+}
+
+/*****************************************************************************
+* LLDispatchListener
+*****************************************************************************/
/**
* Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
* that contains (or derives from) LLDispatchListener need only specify the
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 97e2bdeb57..ff03506e84 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -588,3 +588,16 @@ void LLReqID::stamp(LLSD& response) const
}
response["reqid"] = mReqid;
}
+
+bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey)
+{
+ // Copy 'reply' to modify it.
+ LLSD newreply(reply);
+ // Get the ["reqid"] element from request
+ LLReqID reqID(request);
+ // and copy it to 'newreply'.
+ reqID.stamp(newreply);
+ // Send reply on LLEventPump named in request[replyKey]. Don't forget to
+ // send the modified 'newreply' instead of the original 'reply'.
+ return LLEventPumps::instance().obtain(request[replyKey]).post(newreply);
+}
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 2491cf1371..65b0fef354 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -692,6 +692,20 @@ private:
};
/**
+ * Conventionally send a reply to a request event.
+ *
+ * @a reply is the LLSD reply event to send
+ * @a request is the corresponding LLSD request event
+ * @a replyKey is the key in the @a request event, conventionally ["reply"],
+ * whose value is the name of the LLEventPump on which to send the reply.
+ *
+ * Before sending the reply event, sendReply() copies the ["reqid"] item from
+ * the request to the reply.
+ */
+LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
+ const std::string& replyKey="reply");
+
+/**
* Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We
* provide virtual @c accept_xxx() methods, customization points allowing a
* subclass access to certain data visible at LLEventPump::listen() time.
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 89bc6cca39..f576204511 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -32,6 +32,17 @@
// external library headers
// other Linden headers
-// llinstancetracker.h is presently header-only. This file exists only because our CMake
-// test macro ADD_BUILD_TEST requires it.
-int dummy = 0;
+//static
+void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
+{
+ static std::map<std::string, void *> instances;
+
+ std::string k = info.name();
+ if(instances.find(k) == instances.end())
+ {
+ instances[k] = NULL;
+ }
+
+ return instances[k];
+}
+
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 4945461d62..b971b2f914 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -37,14 +37,21 @@
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
+class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
+{
+ protected:
+ static void * & getInstances(std::type_info const & info);
+};
+
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
/// @NOTE: see explicit specialization below for default KEY==T* case
template<typename T, typename KEY = T*>
-class LLInstanceTracker : boost::noncopyable
+class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef typename std::map<KEY, T*> InstanceMap;
+ typedef LLInstanceTracker<T, KEY> MyT;
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
public:
@@ -99,25 +106,26 @@ private:
static InstanceMap& getMap_()
{
- if (! sInstances)
+ void * & instances = getInstances(typeid(MyT));
+ if (! instances)
{
- sInstances = new InstanceMap;
+ instances = new InstanceMap;
}
- return *sInstances;
+ return * static_cast<InstanceMap*>(instances);
}
private:
KEY mKey;
- static InstanceMap* sInstances;
};
/// explicit specialization for default case where KEY is T*
/// use a simple std::set<T*>
template<typename T>
-class LLInstanceTracker<T, T*>
+class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
{
typedef typename std::set<T*> InstanceSet;
+ typedef LLInstanceTracker<T, T*> MyT;
public:
/// Dereferencing key_iter gives you a T* (since T* is the key)
typedef typename InstanceSet::iterator key_iter;
@@ -172,19 +180,17 @@ protected:
static InstanceSet& getSet_()
{
- if (! sInstances)
+ void * & instances = getInstances(typeid(MyT));
+ if (! instances)
{
- sInstances = new InstanceSet;
+ instances = new InstanceSet;
}
- return *sInstances;
+ return * static_cast<InstanceSet *>(instances);
}
- static InstanceSet* sInstances;
static S32 sIterationNestDepth;
};
-template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL;
-template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL;
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
#endif
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index f8f9ece058..803417d368 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -41,6 +41,7 @@
#include "llsdserialize.h"
#include "stringize.h"
+#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
@@ -571,7 +572,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
-bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
+bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
{
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
@@ -588,6 +589,20 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
// Both are TypeUndefined. There's nothing more to know.
return true;
+ case LLSD::TypeReal:
+ // This is where the 'bits' argument comes in handy. If passed
+ // explicitly, it means to use is_approx_equal_fraction() to compare.
+ if (bits >= 0)
+ {
+ return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
+ }
+ // Otherwise we compare bit representations, and the usual caveats
+ // about comparing floating-point numbers apply. Omitting 'bits' when
+ // comparing Real values is only useful when we expect identical bit
+ // representation for a given Real value, e.g. for integer-valued
+ // Reals.
+ return (lhs.asReal() == rhs.asReal());
+
#define COMPARE_SCALAR(type) \
case LLSD::Type##type: \
/* LLSD::URI has operator!=() but not operator==() */ \
@@ -596,10 +611,6 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
- // The usual caveats about comparing floating-point numbers apply. This is
- // only useful when we expect identical bit representation for a given
- // Real value, e.g. for integer-valued Reals.
- COMPARE_SCALAR(Real);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
@@ -617,7 +628,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
- if (! llsd_equals(*lai, *rai))
+ if (! llsd_equals(*lai, *rai, bits))
return false;
}
// Here we've reached the end of one or the other array. They're equal
@@ -644,7 +655,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
- if (! llsd_equals(lmi->second, rhs[lmi->first]))
+ if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
return false;
}
// We've now established that all the lhs keys have equal values in
@@ -657,7 +668,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs)
// We expect that every possible type() value is specifically handled
// above. Failing to extend this switch to support a new LLSD type is
// an error that must be brought to the coder's attention.
- LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << "): "
+ LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index bb8c0690b1..65c7297cbf 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -123,8 +123,10 @@ LL_COMMON_API BOOL compare_llsd_with_template(
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
-/// Deep equality
-LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs);
+/// Deep equality. If you want to compare LLSD::Real values for approximate
+/// equality rather than bitwise equality, pass @a bits as for
+/// is_approx_equal_fraction().
+LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
// Simple function to copy data out of input & output iterators if
// there is no need for casting.
@@ -138,4 +140,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
return dest;
}
+/*****************************************************************************
+* LLSDArray
+*****************************************************************************/
+/**
+ * Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
+ *
+ * @code
+ * void somefunc(const LLSD&);
+ * ...
+ * somefunc(LLSDArray("text")(17)(3.14));
+ * @endcode
+ *
+ * For completeness, LLSDArray() with no args constructs an empty array, so
+ * <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
+ * above. But for most purposes, LLSD() is already equivalent to an empty
+ * array, and if you explicitly want an empty isArray(), there's
+ * LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
+ * follows the principle of least astonishment.
+ */
+class LLSDArray
+{
+public:
+ LLSDArray():
+ _data(LLSD::emptyArray())
+ {}
+
+ /**
+ * Need an explicit copy constructor. Consider the following:
+ *
+ * @code
+ * LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
+ * (LLSDArray("x")("y")));
+ * @endcode
+ *
+ * The coder intends to construct [[17, 34], ["x", "y"]].
+ *
+ * With the compiler's implicit copy constructor, s/he gets instead
+ * [17, 34, ["x", "y"]].
+ *
+ * The expression LLSDArray(17)(34) constructs an LLSDArray with those two
+ * values. The reader assumes it should be converted to LLSD, as we always
+ * want with LLSDArray, before passing it to the @em outer LLSDArray
+ * constructor! This copy constructor makes that happen.
+ */
+ LLSDArray(const LLSDArray& inner):
+ _data(LLSD::emptyArray())
+ {
+ _data.append(inner);
+ }
+
+ LLSDArray(const LLSD& value):
+ _data(LLSD::emptyArray())
+ {
+ _data.append(value);
+ }
+
+ LLSDArray& operator()(const LLSD& value)
+ {
+ _data.append(value);
+ return *this;
+ }
+
+ operator LLSD() const { return _data; }
+ LLSD get() const { return _data; }
+
+private:
+ LLSD _data;
+};
+
+/*****************************************************************************
+* LLSDMap
+*****************************************************************************/
+/**
+ * Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
+ *
+ * @code
+ * void somefunc(const LLSD&);
+ * ...
+ * somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
+ * @endcode
+ *
+ * For completeness, LLSDMap() with no args constructs an empty map, so
+ * <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
+ * equivalent to the above. But for most purposes, LLSD() is already
+ * equivalent to an empty map, and if you explicitly want an empty isMap(),
+ * there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
+ * constructor follows the principle of least astonishment.
+ */
+class LLSDMap
+{
+public:
+ LLSDMap():
+ _data(LLSD::emptyMap())
+ {}
+ LLSDMap(const LLSD::String& key, const LLSD& value):
+ _data(LLSD::emptyMap())
+ {
+ _data[key] = value;
+ }
+
+ LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
+ {
+ _data[key] = value;
+ return *this;
+ }
+
+ operator LLSD() const { return _data; }
+ LLSD get() const { return _data; }
+
+private:
+ LLSD _data;
+};
+
+/*****************************************************************************
+* LLSDParam
+*****************************************************************************/
+/**
+ * LLSDParam is a customization point for passing LLSD values to function
+ * parameters of more or less arbitrary type. LLSD provides a small set of
+ * native conversions; but if a generic algorithm explicitly constructs an
+ * LLSDParam object in the function's argument list, a consumer can provide
+ * LLSDParam specializations to support more different parameter types than
+ * LLSD's native conversions.
+ *
+ * Usage:
+ *
+ * @code
+ * void somefunc(const paramtype&);
+ * ...
+ * somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
+ * @endcode
+ */
+template <typename T>
+class LLSDParam
+{
+public:
+ /**
+ * Default implementation converts to T on construction, saves converted
+ * value for later retrieval
+ */
+ LLSDParam(const LLSD& value):
+ _value(value)
+ {}
+
+ operator T() const { return _value; }
+
+private:
+ T _value;
+};
+
+/**
+ * Turns out that several target types could accept an LLSD param using any of
+ * a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
+ * std::string. Therefore, the compiler can't decide which LLSD conversion
+ * operator to choose, even though to us it seems obvious. But that's okay, we
+ * can specialize LLSDParam for such target types, explicitly specifying the
+ * desired conversion -- that's part of what LLSDParam is all about. Turns out
+ * we have to do that enough to make it worthwhile generalizing. Use a macro
+ * because I need to specify one of the asReal, etc., explicit conversion
+ * methods as well as a type. If I'm overlooking a clever way to implement
+ * that using a template instead, feel free to reimplement.
+ */
+#define LLSDParam_for(T, AS) \
+template <> \
+class LLSDParam<T> \
+{ \
+public: \
+ LLSDParam(const LLSD& value): \
+ _value(value.AS()) \
+ {} \
+ \
+ operator T() const { return _value; } \
+ \
+private: \
+ T _value; \
+}
+
+LLSDParam_for(float, asReal);
+LLSDParam_for(LLUUID, asUUID);
+LLSDParam_for(LLDate, asDate);
+LLSDParam_for(LLURI, asURI);
+LLSDParam_for(LLSD::Binary, asBinary);
+
+/**
+ * LLSDParam<const char*> is an example of the kind of conversion you can
+ * support with LLSDParam beyond native LLSD conversions. Normally you can't
+ * pass an LLSD object to a function accepting const char* -- but you can
+ * safely pass an LLSDParam<const char*>(yourLLSD).
+ */
+template <>
+class LLSDParam<const char*>
+{
+private:
+ // The difference here is that we store a std::string rather than a const
+ // char*. It's important that the LLSDParam object own the std::string.
+ std::string _value;
+ // We don't bother storing the incoming LLSD object, but we do have to
+ // distinguish whether _value is an empty string because the LLSD object
+ // contains an empty string or because it's isUndefined().
+ bool _undefined;
+
+public:
+ LLSDParam(const LLSD& value):
+ _value(value),
+ _undefined(value.isUndefined())
+ {}
+
+ // The const char* we retrieve is for storage owned by our _value member.
+ // That's how we guarantee that the const char* is valid for the lifetime
+ // of this LLSDParam object. Constructing your LLSDParam in the argument
+ // list should ensure that the LLSDParam object will persist for the
+ // duration of the function call.
+ operator const char*() const
+ {
+ if (_undefined)
+ {
+ // By default, an isUndefined() LLSD object's asString() method
+ // will produce an empty string. But for a function accepting
+ // const char*, it's often important to be able to pass NULL, and
+ // isUndefined() seems like the best way. If you want to pass an
+ // empty string, you can still pass LLSD(""). Without this special
+ // case, though, no LLSD value could pass NULL.
+ return NULL;
+ }
+ return _value.c_str();
+ }
+};
+
+namespace llsd
+{
+
+/*****************************************************************************
+* BOOST_FOREACH() helpers for LLSD
+*****************************************************************************/
+/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
+class inArray
+{
+public:
+ inArray(const LLSD& array):
+ _array(array)
+ {}
+
+ typedef LLSD::array_const_iterator const_iterator;
+ typedef LLSD::array_iterator iterator;
+
+ iterator begin() { return _array.beginArray(); }
+ iterator end() { return _array.endArray(); }
+ const_iterator begin() const { return _array.beginArray(); }
+ const_iterator end() const { return _array.endArray(); }
+
+private:
+ LLSD _array;
+};
+
+/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
+typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
+
+/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
+class inMap
+{
+public:
+ inMap(const LLSD& map):
+ _map(map)
+ {}
+
+ typedef LLSD::map_const_iterator const_iterator;
+ typedef LLSD::map_iterator iterator;
+
+ iterator begin() { return _map.beginMap(); }
+ iterator end() { return _map.endMap(); }
+ const_iterator begin() const { return _map.beginMap(); }
+ const_iterator end() const { return _map.endMap(); }
+
+private:
+ LLSD _map;
+};
+
+} // namespace llsd
+
#endif // LL_LLSDUTIL_H
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index ae2bd0d78b..bd6df962a1 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -29,7 +29,7 @@
const S32 LL_VERSION_MAJOR = 2;
const S32 LL_VERSION_MINOR = 6;
-const S32 LL_VERSION_PATCH = 4;
+const S32 LL_VERSION_PATCH = 5;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp
new file mode 100644
index 0000000000..263c9b171f
--- /dev/null
+++ b/indra/llcommon/tests/lleventdispatcher_test.cpp
@@ -0,0 +1,1324 @@
+/**
+ * @file lleventdispatcher_test.cpp
+ * @author Nat Goodspeed
+ * @date 2011-01-20
+ * @brief Test for lleventdispatcher.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "lleventdispatcher.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "llsd.h"
+#include "llsdutil.h"
+#include "stringize.h"
+#include "tests/wrapllerrs.h"
+
+#include <map>
+#include <string>
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/range.hpp>
+#include <boost/foreach.hpp>
+#define foreach BOOST_FOREACH
+
+#include <boost/lambda/lambda.hpp>
+
+#include <iostream>
+#include <iomanip>
+
+using boost::lambda::constant;
+using boost::lambda::constant_ref;
+using boost::lambda::var;
+
+using namespace llsd;
+
+/*****************************************************************************
+* Output control
+*****************************************************************************/
+#ifdef DEBUG_ON
+using std::cout;
+#else
+static std::ostringstream cout;
+#endif
+
+/*****************************************************************************
+* Example data, functions, classes
+*****************************************************************************/
+// We don't need a whole lot of different arbitrary-params methods, just (no |
+// (const LLSD&) | arbitrary) args (function | static method | non-static
+// method), where 'arbitrary' is (every LLSD datatype + (const char*)).
+// But we need to register each one under different names for the different
+// registration styles. Don't forget LLEventDispatcher subclass methods(const
+// LLSD&).
+
+// However, the number of target parameter conversions we want to try exceeds
+// boost::fusion::invoke()'s supported parameter-list size. Break out two
+// different lists.
+#define NPARAMSa bool b, int i, float f, double d, const char* cp
+#define NPARAMSb const std::string& s, const LLUUID& uuid, const LLDate& date, \
+ const LLURI& uri, const std::vector<U8>& bin
+#define NARGSa b, i, f, d, cp
+#define NARGSb s, uuid, date, uri, bin
+
+// For some registration methods we need methods on a subclass of
+// LLEventDispatcher. To simplify things, we'll use this Dispatcher subclass
+// for all our testing, including testing its own methods.
+class Dispatcher: public LLEventDispatcher
+{
+public:
+ Dispatcher(const std::string& name, const std::string& key):
+ LLEventDispatcher(name, key)
+ {}
+
+ // sensing member, mutable because we want to know when we've reached our
+ // const method too
+ mutable LLSD llsd;
+
+ void method1(const LLSD& obj) { llsd = obj; }
+ void cmethod1(const LLSD& obj) const { llsd = obj; }
+};
+
+// sensing vars, captured in a struct to make it convenient to clear them
+struct Vars
+{
+ LLSD llsd;
+ bool b;
+ int i;
+ float f;
+ double d;
+ // Capture param passed as char*. But merely storing a char* received from
+ // our caller, possibly the .c_str() from a concatenation expression,
+ // would be Bad: the pointer will be invalidated long before we can query
+ // it. We could allocate a new chunk of memory, copy the string data and
+ // point to that instead -- but hey, guess what, we already have a class
+ // that does that!
+ std::string cp;
+ std::string s;
+ LLUUID uuid;
+ LLDate date;
+ LLURI uri;
+ std::vector<U8> bin;
+
+ Vars():
+ // Only need to initialize the POD types, the rest should take care of
+ // default-constructing themselves.
+ b(false),
+ i(0),
+ f(0),
+ d(0)
+ {}
+
+ // Detect any non-default values for convenient testing
+ LLSD inspect() const
+ {
+ LLSD result;
+
+ if (llsd.isDefined())
+ result["llsd"] = llsd;
+ if (b)
+ result["b"] = b;
+ if (i)
+ result["i"] = i;
+ if (f)
+ result["f"] = f;
+ if (d)
+ result["d"] = d;
+ if (! cp.empty())
+ result["cp"] = cp;
+ if (! s.empty())
+ result["s"] = s;
+ if (uuid != LLUUID())
+ result["uuid"] = uuid;
+ if (date != LLDate())
+ result["date"] = date;
+ if (uri != LLURI())
+ result["uri"] = uri;
+ if (! bin.empty())
+ result["bin"] = bin;
+
+ return result;
+ }
+
+ /*------------- no-args (non-const, const, static) methods -------------*/
+ void method0()
+ {
+ cout << "method0()\n";
+ i = 17;
+ }
+
+ void cmethod0() const
+ {
+ cout << 'c';
+ const_cast<Vars*>(this)->method0();
+ }
+
+ static void smethod0();
+
+ /*------------ Callable (non-const, const, static) methods -------------*/
+ void method1(const LLSD& obj)
+ {
+ cout << "method1(" << obj << ")\n";
+ llsd = obj;
+ }
+
+ void cmethod1(const LLSD& obj) const
+ {
+ cout << 'c';
+ const_cast<Vars*>(this)->method1(obj);
+ }
+
+ static void smethod1(const LLSD& obj);
+
+ /*-------- Arbitrary-params (non-const, const, static) methods ---------*/
+ void methodna(NPARAMSa)
+ {
+ // Because our const char* param cp might be NULL, and because we
+ // intend to capture the value in a std::string, have to distinguish
+ // between the NULL value and any non-NULL value. Use a convention
+ // easy for a human reader: enclose any non-NULL value in single
+ // quotes, reserving the unquoted string "NULL" to represent a NULL ptr.
+ std::string vcp;
+ if (cp == NULL)
+ vcp = "NULL";
+ else
+ vcp = std::string("'") + cp + "'";
+
+ cout << "methodna(" << b
+ << ", " << i
+ << ", " << f
+ << ", " << d
+ << ", " << vcp
+ << ")\n";
+
+ this->b = b;
+ this->i = i;
+ this->f = f;
+ this->d = d;
+ this->cp = vcp;
+ }
+
+ void methodnb(NPARAMSb)
+ {
+ std::ostringstream vbin;
+ foreach(U8 byte, bin)
+ {
+ vbin << std::hex << std::setfill('0') << std::setw(2) << unsigned(byte);
+ }
+
+ cout << "methodnb(" << "'" << s << "'"
+ << ", " << uuid
+ << ", " << date
+ << ", '" << uri << "'"
+ << ", " << vbin.str()
+ << ")\n";
+
+ this->s = s;
+ this->uuid = uuid;
+ this->date = date;
+ this->uri = uri;
+ this->bin = bin;
+ }
+
+ void cmethodna(NPARAMSa) const
+ {
+ cout << 'c';
+ const_cast<Vars*>(this)->methodna(NARGSa);
+ }
+
+ void cmethodnb(NPARAMSb) const
+ {
+ cout << 'c';
+ const_cast<Vars*>(this)->methodnb(NARGSb);
+ }
+
+ static void smethodna(NPARAMSa);
+ static void smethodnb(NPARAMSb);
+};
+/*------- Global Vars instance for free functions and static methods -------*/
+static Vars g;
+
+/*------------ Static Vars method implementations reference 'g' ------------*/
+void Vars::smethod0()
+{
+ cout << "smethod0() -> ";
+ g.method0();
+}
+
+void Vars::smethod1(const LLSD& obj)
+{
+ cout << "smethod1(" << obj << ") -> ";
+ g.method1(obj);
+}
+
+void Vars::smethodna(NPARAMSa)
+{
+ cout << "smethodna(...) -> ";
+ g.methodna(NARGSa);
+}
+
+void Vars::smethodnb(NPARAMSb)
+{
+ cout << "smethodnb(...) -> ";
+ g.methodnb(NARGSb);
+}
+
+/*--------------------------- Reset global Vars ----------------------------*/
+void clear()
+{
+ g = Vars();
+}
+
+/*------------------- Free functions also reference 'g' --------------------*/
+void free0()
+{
+ cout << "free0() -> ";
+ g.method0();
+}
+
+void free1(const LLSD& obj)
+{
+ cout << "free1(" << obj << ") -> ";
+ g.method1(obj);
+}
+
+void freena(NPARAMSa)
+{
+ cout << "freena(...) -> ";
+ g.methodna(NARGSa);
+}
+
+void freenb(NPARAMSb)
+{
+ cout << "freenb(...) -> ";
+ g.methodnb(NARGSb);
+}
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct lleventdispatcher_data
+ {
+ WrapLL_ERRS redirect;
+ Dispatcher work;
+ Vars v;
+ std::string name, desc;
+ // Capture our own copy of all registered functions' descriptions
+ typedef std::map<std::string, std::string> DescMap;
+ DescMap descs;
+ // Capture the Vars instance on which we expect each function to operate
+ typedef std::map<std::string, Vars*> VarsMap;
+ VarsMap funcvars;
+ // Required structure for Callables with requirements
+ LLSD required;
+ // Parameter names for freena(), freenb()
+ LLSD params;
+ // Full, partial defaults arrays for params for freena(), freenb()
+ LLSD dft_array_full, dft_array_partial;
+ // Start index of partial defaults arrays
+ const LLSD::Integer partial_offset;
+ // Full, partial defaults maps for params for freena(), freenb()
+ LLSD dft_map_full, dft_map_partial;
+ // Most of the above are indexed by "a" or "b". Useful to have an
+ // array containing those strings for iterating.
+ std::vector<LLSD::String> ab;
+
+ lleventdispatcher_data():
+ work("test dispatcher", "op"),
+ // map {d=double, array=[3 elements]}
+ required(LLSDMap("d", LLSD::Real(0))("array", LLSDArray(LLSD())(LLSD())(LLSD()))),
+ // first several params are required, last couple optional
+ partial_offset(3)
+ {
+ // This object is reconstructed for every test<n> method. But
+ // clear global variables every time too.
+ ::clear();
+
+ const char* abs[] = { "a", "b" };
+ ab.assign(boost::begin(abs), boost::end(abs));
+
+ // Registration cases:
+ // - (Callable | subclass const method | subclass non-const method |
+ // non-subclass method) (with | without) required
+ // - (Free function | static method | non-static method), (no | arbitrary) params,
+ // array style
+ // - (Free function | static method | non-static method), (no | arbitrary) params,
+ // map style, (empty | partial | full) (array | map) defaults
+ // - Map-style errors:
+ // - (scalar | map) param names
+ // - defaults scalar
+ // - defaults array longer than params array
+ // - defaults map with plural unknown param names
+
+ // I hate to have to write things twice, because of having to keep
+ // them consistent. If we had variadic functions, addf() would be
+ // a variadic method, capturing the name and desc and passing them
+ // plus "everything else" to work.add(). If I could return a pair
+ // and use that pair as the first two args to work.add(), I'd do
+ // that. But the best I can do with present C++ is to set two
+ // instance variables as a side effect of addf(), and pass those
+ // variables to each work.add() call. :-P
+
+ /*------------------------- Callables --------------------------*/
+
+ // Arbitrary Callable with/out required params
+ addf("free1", "free1", &g);
+ work.add(name, desc, free1);
+ addf("free1_req", "free1", &g);
+ work.add(name, desc, free1, required);
+ // Subclass non-const method with/out required params
+ addf("Dmethod1", "method1", NULL);
+ work.add(name, desc, &Dispatcher::method1);
+ addf("Dmethod1_req", "method1", NULL);
+ work.add(name, desc, &Dispatcher::method1, required);
+ // Subclass const method with/out required params
+ addf("Dcmethod1", "cmethod1", NULL);
+ work.add(name, desc, &Dispatcher::cmethod1);
+ addf("Dcmethod1_req", "cmethod1", NULL);
+ work.add(name, desc, &Dispatcher::cmethod1, required);
+ // Non-subclass method with/out required params
+ addf("method1", "method1", &v);
+ work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1));
+ addf("method1_req", "method1", &v);
+ work.add(name, desc, boost::bind(&Vars::method1, boost::ref(v), _1), required);
+
+ /*--------------- Arbitrary params, array style ----------------*/
+
+ // (Free function | static method) with (no | arbitrary) params, array style
+ addf("free0_array", "free0", &g);
+ work.add(name, desc, free0);
+ addf("freena_array", "freena", &g);
+ work.add(name, desc, freena);
+ addf("freenb_array", "freenb", &g);
+ work.add(name, desc, freenb);
+ addf("smethod0_array", "smethod0", &g);
+ work.add(name, desc, &Vars::smethod0);
+ addf("smethodna_array", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna);
+ addf("smethodnb_array", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb);
+ // Non-static method with (no | arbitrary) params, array style
+ addf("method0_array", "method0", &v);
+ work.add(name, desc, &Vars::method0, boost::lambda::var(v));
+ addf("methodna_array", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, boost::lambda::var(v));
+ addf("methodnb_array", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, boost::lambda::var(v));
+
+ /*---------------- Arbitrary params, map style -----------------*/
+
+ // We lay out each params list as an array, also each array of
+ // default values we'll register. We'll zip these into
+ // (param=value) maps. Why not define them as maps and just
+ // extract the keys and values to arrays? Because that wouldn't
+ // give us the right params-list order.
+
+ // freena(), methodna(), cmethodna(), smethodna() all take same param list.
+ // Same for freenb() et al.
+ params = LLSDMap("a", LLSDArray("b")("i")("f")("d")("cp"))
+ ("b", LLSDArray("s")("uuid")("date")("uri")("bin"));
+ cout << "params:\n" << params << "\nparams[\"a\"]:\n" << params["a"] << "\nparams[\"b\"]:\n" << params["b"] << std::endl;
+ // default LLSD::Binary value
+ std::vector<U8> binary;
+ for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11)
+ {
+ binary.push_back(h);
+ }
+ // Full defaults arrays. We actually don't care what the LLUUID or
+ // LLDate values are, as long as they're different from the
+ // LLUUID() and LLDate() default values so inspect() will report
+ // them.
+ dft_array_full = LLSDMap("a", LLSDArray(true)(17)(3.14)(123456.78)("classic"))
+ ("b", LLSDArray("string")
+ (LLUUID::generateNewID())
+ (LLDate::now())
+ (LLURI("http://www.ietf.org/rfc/rfc3986.txt"))
+ (binary));
+ cout << "dft_array_full:\n" << dft_array_full << std::endl;
+ // Partial defaults arrays.
+ foreach(LLSD::String a, ab)
+ {
+ LLSD::Integer partition(std::min(partial_offset, dft_array_full[a].size()));
+ dft_array_partial[a] =
+ llsd_copy_array(dft_array_full[a].beginArray() + partition,
+ dft_array_full[a].endArray());
+ }
+ cout << "dft_array_partial:\n" << dft_array_partial << std::endl;
+
+ foreach(LLSD::String a, ab)
+ {
+ // Generate full defaults maps by zipping (params, dft_array_full).
+ dft_map_full[a] = zipmap(params[a], dft_array_full[a]);
+
+ // Generate partial defaults map by zipping alternate entries from
+ // (params, dft_array_full). Part of the point of using map-style
+ // defaults is to allow any subset of the target function's
+ // parameters to be optional, not just the rightmost.
+ for (LLSD::Integer ix = 0, ixend = params[a].size(); ix < ixend; ix += 2)
+ {
+ dft_map_partial[a][params[a][ix].asString()] = dft_array_full[a][ix];
+ }
+ }
+ cout << "dft_map_full:\n" << dft_map_full << "\ndft_map_partial:\n" << dft_map_partial << '\n';
+
+ // (Free function | static method) with (no | arbitrary) params,
+ // map style, no (empty array) defaults
+ addf("free0_map", "free0", &g);
+ work.add(name, desc, free0, LLSD::emptyArray());
+ addf("smethod0_map", "smethod0", &g);
+ work.add(name, desc, &Vars::smethod0, LLSD::emptyArray());
+ addf("freena_map_allreq", "freena", &g);
+ work.add(name, desc, freena, params["a"]);
+ addf("freenb_map_allreq", "freenb", &g);
+ work.add(name, desc, freenb, params["b"]);
+ addf("smethodna_map_allreq", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna, params["a"]);
+ addf("smethodnb_map_allreq", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb, params["b"]);
+ // Non-static method with (no | arbitrary) params, map style, no
+ // (empty array) defaults
+ addf("method0_map", "method0", &v);
+ work.add(name, desc, &Vars::method0, var(v), LLSD::emptyArray());
+ addf("methodna_map_allreq", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, var(v), params["a"]);
+ addf("methodnb_map_allreq", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, var(v), params["b"]);
+
+ // Except for the "more (array | map) defaults than params" error
+ // cases, tested separately below, the (partial | full)(array |
+ // map) defaults cases don't apply to no-params functions/methods.
+ // So eliminate free0, smethod0, method0 from the cases below.
+
+ // (Free function | static method) with arbitrary params, map
+ // style, partial (array | map) defaults
+ addf("freena_map_leftreq", "freena", &g);
+ work.add(name, desc, freena, params["a"], dft_array_partial["a"]);
+ addf("freenb_map_leftreq", "freenb", &g);
+ work.add(name, desc, freenb, params["b"], dft_array_partial["b"]);
+ addf("smethodna_map_leftreq", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna, params["a"], dft_array_partial["a"]);
+ addf("smethodnb_map_leftreq", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_partial["b"]);
+ addf("freena_map_skipreq", "freena", &g);
+ work.add(name, desc, freena, params["a"], dft_map_partial["a"]);
+ addf("freenb_map_skipreq", "freenb", &g);
+ work.add(name, desc, freenb, params["b"], dft_map_partial["b"]);
+ addf("smethodna_map_skipreq", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna, params["a"], dft_map_partial["a"]);
+ addf("smethodnb_map_skipreq", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_partial["b"]);
+ // Non-static method with arbitrary params, map style, partial
+ // (array | map) defaults
+ addf("methodna_map_leftreq", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_partial["a"]);
+ addf("methodnb_map_leftreq", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_partial["b"]);
+ addf("methodna_map_skipreq", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_partial["a"]);
+ addf("methodnb_map_skipreq", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_partial["b"]);
+
+ // (Free function | static method) with arbitrary params, map
+ // style, full (array | map) defaults
+ addf("freena_map_adft", "freena", &g);
+ work.add(name, desc, freena, params["a"], dft_array_full["a"]);
+ addf("freenb_map_adft", "freenb", &g);
+ work.add(name, desc, freenb, params["b"], dft_array_full["b"]);
+ addf("smethodna_map_adft", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna, params["a"], dft_array_full["a"]);
+ addf("smethodnb_map_adft", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb, params["b"], dft_array_full["b"]);
+ addf("freena_map_mdft", "freena", &g);
+ work.add(name, desc, freena, params["a"], dft_map_full["a"]);
+ addf("freenb_map_mdft", "freenb", &g);
+ work.add(name, desc, freenb, params["b"], dft_map_full["b"]);
+ addf("smethodna_map_mdft", "smethodna", &g);
+ work.add(name, desc, &Vars::smethodna, params["a"], dft_map_full["a"]);
+ addf("smethodnb_map_mdft", "smethodnb", &g);
+ work.add(name, desc, &Vars::smethodnb, params["b"], dft_map_full["b"]);
+ // Non-static method with arbitrary params, map style, full
+ // (array | map) defaults
+ addf("methodna_map_adft", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_array_full["a"]);
+ addf("methodnb_map_adft", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_array_full["b"]);
+ addf("methodna_map_mdft", "methodna", &v);
+ work.add(name, desc, &Vars::methodna, var(v), params["a"], dft_map_full["a"]);
+ addf("methodnb_map_mdft", "methodnb", &v);
+ work.add(name, desc, &Vars::methodnb, var(v), params["b"], dft_map_full["b"]);
+
+ // All the above are expected to succeed, and are setup for the
+ // tests to follow. Registration error cases are exercised as
+ // tests rather than as test setup.
+ }
+
+ void addf(const std::string& n, const std::string& d, Vars* v)
+ {
+ // This method is to capture in our own DescMap the name and
+ // description of every registered function, for metadata query
+ // testing.
+ descs[n] = d;
+ // Also capture the Vars instance on which each function should operate.
+ funcvars[n] = v;
+ // See constructor for rationale for setting these instance vars.
+ this->name = n;
+ this->desc = d;
+ }
+
+ void verify_descs()
+ {
+ // Copy descs to a temp map of same type.
+ DescMap forgotten(descs.begin(), descs.end());
+ // LLEventDispatcher intentionally provides only const_iterator:
+ // since dereferencing that iterator generates values on the fly,
+ // it's meaningless to have a modifiable iterator. But since our
+ // 'work' object isn't const, by default BOOST_FOREACH() wants to
+ // use non-const iterators. Persuade it to use the const_iterator.
+ foreach(LLEventDispatcher::NameDesc nd, const_cast<const Dispatcher&>(work))
+ {
+ DescMap::iterator found = forgotten.find(nd.first);
+ ensure(STRINGIZE("LLEventDispatcher records function '" << nd.first
+ << "' we didn't enter"),
+ found != forgotten.end());
+ ensure_equals(STRINGIZE("LLEventDispatcher desc '" << nd.second <<
+ "' doesn't match what we entered: '" << found->second << "'"),
+ nd.second, found->second);
+ // found in our map the name from LLEventDispatcher, good, erase
+ // our map entry
+ forgotten.erase(found);
+ }
+ if (! forgotten.empty())
+ {
+ std::ostringstream out;
+ out << "LLEventDispatcher failed to report";
+ const char* delim = ": ";
+ foreach(const DescMap::value_type& fme, forgotten)
+ {
+ out << delim << fme.first;
+ delim = ", ";
+ }
+ ensure(out.str(), false);
+ }
+ }
+
+ Vars* varsfor(const std::string& name)
+ {
+ VarsMap::const_iterator found = funcvars.find(name);
+ ensure(STRINGIZE("No Vars* for " << name), found != funcvars.end());
+ ensure(STRINGIZE("NULL Vars* for " << name), found->second);
+ return found->second;
+ }
+
+ void ensure_has(const std::string& outer, const std::string& inner)
+ {
+ ensure(STRINGIZE("'" << outer << "' does not contain '" << inner << "'").c_str(),
+ outer.find(inner) != std::string::npos);
+ }
+
+ void call_exc(const std::string& func, const LLSD& args, const std::string& exc_frag)
+ {
+ std::string threw;
+ try
+ {
+ work(func, args);
+ }
+ catch (const std::runtime_error& e)
+ {
+ cout << "*** " << e.what() << '\n';
+ threw = e.what();
+ }
+ ensure_has(threw, exc_frag);
+ }
+
+ LLSD getMetadata(const std::string& name)
+ {
+ LLSD meta(work.getMetadata(name));
+ ensure(STRINGIZE("No metadata for " << name), meta.isDefined());
+ return meta;
+ }
+
+ // From two related LLSD arrays, e.g. a param-names array and a values
+ // array, zip them together into an LLSD map.
+ LLSD zipmap(const LLSD& keys, const LLSD& values)
+ {
+ LLSD map;
+ for (LLSD::Integer i = 0, iend = keys.size(); i < iend; ++i)
+ {
+ // Have to select asString() since you can index an LLSD
+ // object with either String or Integer.
+ map[keys[i].asString()] = values[i];
+ }
+ return map;
+ }
+
+ // If I call this ensure_equals(), it blocks visibility of all other
+ // ensure_equals() overloads. Normally I could say 'using
+ // baseclass::ensure_equals;' and fix that, but I don't know what the
+ // base class is!
+ void ensure_llsd(const std::string& msg, const LLSD& actual, const LLSD& expected, U32 bits)
+ {
+ std::ostringstream out;
+ if (! msg.empty())
+ {
+ out << msg << ": ";
+ }
+ out << "expected " << expected << ", actual " << actual;
+ ensure(out.str(), llsd_equals(actual, expected, bits));
+ }
+
+ void ensure_llsd(const LLSD& actual, const LLSD& expected, U32 bits)
+ {
+ ensure_llsd("", actual, expected, bits);
+ }
+ };
+ typedef test_group<lleventdispatcher_data> lleventdispatcher_group;
+ typedef lleventdispatcher_group::object object;
+ lleventdispatcher_group lleventdispatchergrp("lleventdispatcher");
+
+ // Call cases:
+ // - (try_call | call) (explicit name | event key) (real | bogus) name
+ // - Callable with args that (do | do not) match required
+ // - (Free function | non-static method), no args, (array | map) style
+ // - (Free function | non-static method), arbitrary args,
+ // (array style with (scalar | map) | map style with scalar)
+ // - (Free function | non-static method), arbitrary args, array style with
+ // array (too short | too long | just right)
+ // [trap LL_WARNS for too-long case?]
+ // - (Free function | non-static method), arbitrary args, map style with
+ // (array | map) (all | too many | holes (with | without) defaults)
+ // - const char* param gets ("" | NULL)
+
+ // Query cases:
+ // - Iterate over all (with | without) remove()
+ // - getDispatchKey()
+ // - Callable style (with | without) required
+ // - (Free function | non-static method), array style, (no | arbitrary) params
+ // - (Free function | non-static method), map style, (no | arbitrary) params,
+ // (empty | full | partial (array | map)) defaults
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("map-style registration with non-array params");
+ // Pass "param names" as scalar or as map
+ LLSD attempts(LLSDArray(17)(LLSDMap("pi", 3.14)("two", 2)));
+ foreach(LLSD ae, inArray(attempts))
+ {
+ std::string threw;
+ try
+ {
+ work.add("freena_err", "freena", freena, ae);
+ }
+ catch (const std::exception& e)
+ {
+ threw = e.what();
+ }
+ ensure_has(threw, "must be an array");
+ }
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("map-style registration with badly-formed defaults");
+ std::string threw;
+ try
+ {
+ work.add("freena_err", "freena", freena, LLSDArray("a")("b"), 17);
+ }
+ catch (const std::exception& e)
+ {
+ threw = e.what();
+ }
+ ensure_has(threw, "must be a map or an array");
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("map-style registration with too many array defaults");
+ std::string threw;
+ try
+ {
+ work.add("freena_err", "freena", freena,
+ LLSDArray("a")("b"),
+ LLSDArray(17)(0.9)("gack"));
+ }
+ catch (const std::exception& e)
+ {
+ threw = e.what();
+ }
+ ensure_has(threw, "shorter than");
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("map-style registration with too many map defaults");
+ std::string threw;
+ try
+ {
+ work.add("freena_err", "freena", freena,
+ LLSDArray("a")("b"),
+ LLSDMap("b", 17)("foo", 3.14)("bar", "sinister"));
+ }
+ catch (const std::exception& e)
+ {
+ threw = e.what();
+ }
+ ensure_has(threw, "nonexistent params");
+ ensure_has(threw, "foo");
+ ensure_has(threw, "bar");
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("query all");
+ verify_descs();
+ }
+
+ template<> template<>
+ void object::test<6>()
+ {
+ set_test_name("query all with remove()");
+ ensure("remove('bogus') returned true", ! work.remove("bogus"));
+ ensure("remove('real') returned false", work.remove("free1"));
+ // Of course, remove that from 'descs' too...
+ descs.erase("free1");
+ verify_descs();
+ }
+
+ template<> template<>
+ void object::test<7>()
+ {
+ set_test_name("getDispatchKey()");
+ ensure_equals(work.getDispatchKey(), "op");
+ }
+
+ template<> template<>
+ void object::test<8>()
+ {
+ set_test_name("query Callables with/out required params");
+ LLSD names(LLSDArray("free1")("Dmethod1")("Dcmethod1")("method1"));
+ foreach(LLSD nm, inArray(names))
+ {
+ LLSD metadata(getMetadata(nm));
+ ensure_equals("name mismatch", metadata["name"], nm);
+ ensure_equals(metadata["desc"].asString(), descs[nm]);
+ ensure("should not have required structure", metadata["required"].isUndefined());
+ ensure("should not have optional", metadata["optional"].isUndefined());
+
+ std::string name_req(nm.asString() + "_req");
+ metadata = getMetadata(name_req);
+ ensure_equals(metadata["name"].asString(), name_req);
+ ensure_equals(metadata["desc"].asString(), descs[name_req]);
+ ensure_equals("required mismatch", required, metadata["required"]);
+ ensure("should not have optional", metadata["optional"].isUndefined());
+ }
+ }
+
+ template<> template<>
+ void object::test<9>()
+ {
+ set_test_name("query array-style functions/methods");
+ // Associate each registered name with expected arity.
+ LLSD expected(LLSDArray
+ (LLSDArray
+ (0)(LLSDArray("free0_array")("smethod0_array")("method0_array")))
+ (LLSDArray
+ (5)(LLSDArray("freena_array")("smethodna_array")("methodna_array")))
+ (LLSDArray
+ (5)(LLSDArray("freenb_array")("smethodnb_array")("methodnb_array"))));
+ foreach(LLSD ae, inArray(expected))
+ {
+ LLSD::Integer arity(ae[0].asInteger());
+ LLSD names(ae[1]);
+ LLSD req(LLSD::emptyArray());
+ if (arity)
+ req[arity - 1] = LLSD();
+ foreach(LLSD nm, inArray(names))
+ {
+ LLSD metadata(getMetadata(nm));
+ ensure_equals("name mismatch", metadata["name"], nm);
+ ensure_equals(metadata["desc"].asString(), descs[nm]);
+ ensure_equals(STRINGIZE("mismatched required for " << nm.asString()),
+ metadata["required"], req);
+ ensure("should not have optional", metadata["optional"].isUndefined());
+ }
+ }
+ }
+
+ template<> template<>
+ void object::test<10>()
+ {
+ set_test_name("query map-style no-params functions/methods");
+ // - (Free function | non-static method), map style, no params (ergo
+ // no defaults)
+ LLSD names(LLSDArray("free0_map")("smethod0_map")("method0_map"));
+ foreach(LLSD nm, inArray(names))
+ {
+ LLSD metadata(getMetadata(nm));
+ ensure_equals("name mismatch", metadata["name"], nm);
+ ensure_equals(metadata["desc"].asString(), descs[nm]);
+ ensure("should not have required",
+ (metadata["required"].isUndefined() || metadata["required"].size() == 0));
+ ensure("should not have optional", metadata["optional"].isUndefined());
+ }
+ }
+
+ template<> template<>
+ void object::test<11>()
+ {
+ set_test_name("query map-style arbitrary-params functions/methods: "
+ "full array defaults vs. full map defaults");
+ // With functions registered with no defaults ("_allreq" suffixes),
+ // there is of course no difference between array defaults and map
+ // defaults. (We don't even bother registering with LLSD::emptyArray()
+ // vs. LLSD::emptyMap().) With functions registered with all defaults,
+ // there should (!) be no difference beween array defaults and map
+ // defaults. Verify, so we can ignore the distinction for all other
+ // tests.
+ LLSD equivalences(LLSDArray
+ (LLSDArray("freena_map_adft")("freena_map_mdft"))
+ (LLSDArray("freenb_map_adft")("freenb_map_mdft"))
+ (LLSDArray("smethodna_map_adft")("smethodna_map_mdft"))
+ (LLSDArray("smethodnb_map_adft")("smethodnb_map_mdft"))
+ (LLSDArray("methodna_map_adft")("methodna_map_mdft"))
+ (LLSDArray("methodnb_map_adft")("methodnb_map_mdft")));
+ foreach(LLSD eq, inArray(equivalences))
+ {
+ LLSD adft(eq[0]);
+ LLSD mdft(eq[1]);
+ // We can't just compare the results of the two getMetadata()
+ // calls, because they contain ["name"], which are different. So
+ // capture them, verify that each ["name"] is as expected, then
+ // remove for comparing the rest.
+ LLSD ameta(getMetadata(adft));
+ LLSD mmeta(getMetadata(mdft));
+ ensure_equals("adft name", adft, ameta["name"]);
+ ensure_equals("mdft name", mdft, mmeta["name"]);
+ ameta.erase("name");
+ mmeta.erase("name");
+ ensure_equals(STRINGIZE("metadata for " << adft.asString()
+ << " vs. " << mdft.asString()),
+ ameta, mmeta);
+ }
+ }
+
+ template<> template<>
+ void object::test<12>()
+ {
+ set_test_name("query map-style arbitrary-params functions/methods");
+ // - (Free function | non-static method), map style, arbitrary params,
+ // (empty | full | partial (array | map)) defaults
+
+ // Generate maps containing all parameter names for cases in which all
+ // params are required. Also maps containing left requirements for
+ // partial defaults arrays. Also defaults maps from defaults arrays.
+ LLSD allreq, leftreq, rightdft;
+ foreach(LLSD::String a, ab)
+ {
+ // The map in which all params are required uses params[a] as
+ // keys, with all isUndefined() as values. We can accomplish that
+ // by passing zipmap() an empty values array.
+ allreq[a] = zipmap(params[a], LLSD::emptyArray());
+ // Same for leftreq, save that we use the subset of the params not
+ // supplied by dft_array_partial[a].
+ LLSD::Integer partition(params[a].size() - dft_array_partial[a].size());
+ leftreq[a] = zipmap(llsd_copy_array(params[a].beginArray(),
+ params[a].beginArray() + partition),
+ LLSD::emptyArray());
+ // Generate map pairing dft_array_partial[a] values with their
+ // param names.
+ rightdft[a] = zipmap(llsd_copy_array(params[a].beginArray() + partition,
+ params[a].endArray()),
+ dft_array_partial[a]);
+ }
+ cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl;
+
+ // Generate maps containing parameter names not provided by the
+ // dft_map_partial maps.
+ LLSD skipreq(allreq);
+ foreach(LLSD::String a, ab)
+ {
+ foreach(const MapEntry& me, inMap(dft_map_partial[a]))
+ {
+ skipreq[a].erase(me.first);
+ }
+ }
+ cout << "skipreq:\n" << skipreq << std::endl;
+
+ LLSD groups(LLSDArray // array of groups
+
+ (LLSDArray // group
+ (LLSDArray("freena_map_allreq")("smethodna_map_allreq")("methodna_map_allreq"))
+ (LLSDArray(allreq["a"])(LLSD()))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freenb_map_allreq")("smethodnb_map_allreq")("methodnb_map_allreq"))
+ (LLSDArray(allreq["b"])(LLSD()))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freena_map_leftreq")("smethodna_map_leftreq")("methodna_map_leftreq"))
+ (LLSDArray(leftreq["a"])(rightdft["a"]))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freenb_map_leftreq")("smethodnb_map_leftreq")("methodnb_map_leftreq"))
+ (LLSDArray(leftreq["b"])(rightdft["b"]))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freena_map_skipreq")("smethodna_map_skipreq")("methodna_map_skipreq"))
+ (LLSDArray(skipreq["a"])(dft_map_partial["a"]))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freenb_map_skipreq")("smethodnb_map_skipreq")("methodnb_map_skipreq"))
+ (LLSDArray(skipreq["b"])(dft_map_partial["b"]))) // required, optional
+
+ // We only need mention the full-map-defaults ("_mdft" suffix)
+ // registrations, having established their equivalence with the
+ // full-array-defaults ("_adft" suffix) registrations in another test.
+ (LLSDArray // group
+ (LLSDArray("freena_map_mdft")("smethodna_map_mdft")("methodna_map_mdft"))
+ (LLSDArray(LLSD::emptyMap())(dft_map_full["a"]))) // required, optional
+
+ (LLSDArray // group
+ (LLSDArray("freenb_map_mdft")("smethodnb_map_mdft")("methodnb_map_mdft"))
+ (LLSDArray(LLSD::emptyMap())(dft_map_full["b"])))); // required, optional
+
+ foreach(LLSD grp, inArray(groups))
+ {
+ // Internal structure of each group in 'groups':
+ LLSD names(grp[0]);
+ LLSD required(grp[1][0]);
+ LLSD optional(grp[1][1]);
+ cout << "For " << names << ",\n" << "required:\n" << required << "\noptional:\n" << optional << std::endl;
+
+ // Loop through 'names'
+ foreach(LLSD nm, inArray(names))
+ {
+ LLSD metadata(getMetadata(nm));
+ ensure_equals("name mismatch", metadata["name"], nm);
+ ensure_equals(nm.asString(), metadata["desc"].asString(), descs[nm]);
+ ensure_equals(STRINGIZE(nm << " required mismatch"),
+ metadata["required"], required);
+ ensure_equals(STRINGIZE(nm << " optional mismatch"),
+ metadata["optional"], optional);
+ }
+ }
+ }
+
+ template<> template<>
+ void object::test<13>()
+ {
+ set_test_name("try_call()");
+ ensure("try_call(bogus name, LLSD()) returned true", ! work.try_call("freek", LLSD()));
+ ensure("try_call(bogus name) returned true", ! work.try_call(LLSDMap("op", "freek")));
+ ensure("try_call(real name, LLSD()) returned false", work.try_call("free0_array", LLSD()));
+ ensure("try_call(real name) returned false", work.try_call(LLSDMap("op", "free0_map")));
+ }
+
+ template<> template<>
+ void object::test<14>()
+ {
+ set_test_name("call with bad name");
+ call_exc("freek", LLSD(), "not found");
+ // We don't have a comparable helper function for the one-arg
+ // operator() method, and it's not worth building one just for this
+ // case. Write it out.
+ std::string threw;
+ try
+ {
+ work(LLSDMap("op", "freek"));
+ }
+ catch (const std::runtime_error& e)
+ {
+ cout << "*** " << e.what() << "\n";
+ threw = e.what();
+ }
+ ensure_has(threw, "bad");
+ ensure_has(threw, "op");
+ ensure_has(threw, "freek");
+ }
+
+ template<> template<>
+ void object::test<15>()
+ {
+ set_test_name("call with event key");
+ // We don't need a separate test for operator()(string, LLSD) with
+ // valid name, because all the rest of the tests exercise that case.
+ // The one we don't exercise elsewhere is operator()(LLSD) with valid
+ // name, so here it is.
+ work(LLSDMap("op", "free0_map"));
+ ensure_equals(g.i, 17);
+ }
+
+ // Cannot be defined inside function body... remind me again why we use C++... :-P
+ struct CallablesTriple
+ {
+ std::string name, name_req;
+ LLSD& llsd;
+ };
+
+ template<> template<>
+ void object::test<16>()
+ {
+ set_test_name("call Callables");
+ CallablesTriple tests[] =
+ {
+ { "free1", "free1_req", g.llsd },
+ { "Dmethod1", "Dmethod1_req", work.llsd },
+ { "Dcmethod1", "Dcmethod1_req", work.llsd },
+ { "method1", "method1_req", v.llsd }
+ };
+ // Arbitrary LLSD value that we should be able to pass to Callables
+ // without 'required', but should not be able to pass to Callables
+ // with 'required'.
+ LLSD answer(42);
+ // LLSD value matching 'required' according to llsd_matches() rules.
+ LLSD matching(LLSDMap("d", 3.14)("array", LLSDArray("answer")(true)(answer)));
+ // Okay, walk through 'tests'.
+ foreach(const CallablesTriple& tr, tests)
+ {
+ // Should be able to pass 'answer' to Callables registered
+ // without 'required'.
+ work(tr.name, answer);
+ ensure_equals("answer mismatch", tr.llsd, answer);
+ // Should NOT be able to pass 'answer' to Callables registered
+ // with 'required'.
+ call_exc(tr.name_req, answer, "bad request");
+ // But SHOULD be able to pass 'matching' to Callables registered
+ // with 'required'.
+ work(tr.name_req, matching);
+ ensure_equals("matching mismatch", tr.llsd, matching);
+ }
+ }
+
+ template<> template<>
+ void object::test<17>()
+ {
+ set_test_name("passing wrong args to (map | array)-style registrations");
+
+ // Pass scalar/map to array-style functions, scalar/array to map-style
+ // functions. As that validation happens well before we engage the
+ // argument magic, it seems pointless to repeat this with every
+ // variation: (free function | non-static method), (no | arbitrary)
+ // args. We should only need to engage it for one map-style
+ // registration and one array-style registration.
+ std::string array_exc("needs an args array");
+ call_exc("free0_array", 17, array_exc);
+ call_exc("free0_array", LLSDMap("pi", 3.14), array_exc);
+
+ std::string map_exc("needs a map");
+ call_exc("free0_map", 17, map_exc);
+ // Passing an array to a map-style function works now! No longer an
+ // error case!
+// call_exc("free0_map", LLSDArray("a")("b"), map_exc);
+ }
+
+ template<> template<>
+ void object::test<18>()
+ {
+ set_test_name("call no-args functions");
+ LLSD names(LLSDArray
+ ("free0_array")("free0_map")
+ ("smethod0_array")("smethod0_map")
+ ("method0_array")("method0_map"));
+ foreach(LLSD name, inArray(names))
+ {
+ // Look up the Vars instance for this function.
+ Vars* vars(varsfor(name));
+ // Both the global and stack Vars instances are automatically
+ // cleared at the start of each test<n> method. But since we're
+ // calling these things several different times in the same
+ // test<n> method, manually reset the Vars between each.
+ *vars = Vars();
+ ensure_equals(vars->i, 0);
+ // call function with empty array (or LLSD(), should be equivalent)
+ work(name, LLSD());
+ ensure_equals(vars->i, 17);
+ }
+ }
+
+ // Break out this data because we use it in a couple different tests.
+ LLSD array_funcs(LLSDArray
+ (LLSDMap("a", "freena_array") ("b", "freenb_array"))
+ (LLSDMap("a", "smethodna_array")("b", "smethodnb_array"))
+ (LLSDMap("a", "methodna_array") ("b", "methodnb_array")));
+
+ template<> template<>
+ void object::test<19>()
+ {
+ set_test_name("call array-style functions with too-short arrays");
+ // Could have two different too-short arrays, one for *na and one for
+ // *nb, but since they both take 5 params...
+ LLSD tooshort(LLSDArray("this")("array")("too")("short"));
+ foreach(const LLSD& funcsab, inArray(array_funcs))
+ {
+ foreach(const llsd::MapEntry& e, inMap(funcsab))
+ {
+ call_exc(e.second, tooshort, "requires more arguments");
+ }
+ }
+ }
+
+ template<> template<>
+ void object::test<20>()
+ {
+ set_test_name("call array-style functions with (just right | too long) arrays");
+ std::vector<U8> binary;
+ for (size_t h(0x01), i(0); i < 5; h+= 0x22, ++i)
+ {
+ binary.push_back(h);
+ }
+ LLSD args(LLSDMap("a", LLSDArray(true)(17)(3.14)(123.456)("char*"))
+ ("b", LLSDArray("string")
+ (LLUUID("01234567-89ab-cdef-0123-456789abcdef"))
+ (LLDate("2011-02-03T15:07:00Z"))
+ (LLURI("http://secondlife.com"))
+ (binary)));
+ LLSD argsplus(args);
+ argsplus["a"].append("bogus");
+ argsplus["b"].append("bogus");
+ LLSD expect;
+ foreach(LLSD::String a, ab)
+ {
+ expect[a] = zipmap(params[a], args[a]);
+ }
+ // Adjust expect["a"]["cp"] for special Vars::cp treatment.
+ expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
+ cout << "expect: " << expect << '\n';
+
+ // Use substantially the same logic for args and argsplus
+ LLSD argsarrays(LLSDArray(args)(argsplus));
+ // So i==0 selects 'args', i==1 selects argsplus
+ for (LLSD::Integer i(0), iend(argsarrays.size()); i < iend; ++i)
+ {
+ foreach(const LLSD& funcsab, inArray(array_funcs))
+ {
+ foreach(LLSD::String a, ab)
+ {
+ // Reset the Vars instance before each call
+ Vars* vars(varsfor(funcsab[a]));
+ *vars = Vars();
+ work(funcsab[a], argsarrays[i][a]);
+ ensure_llsd(STRINGIZE(funcsab[a].asString() <<
+ ": expect[\"" << a << "\"] mismatch"),
+ vars->inspect(), expect[a], 7); // 7 bits ~= 2 decimal digits
+
+ // TODO: in the i==1 or argsplus case, intercept LL_WARNS
+ // output? Even without that, using argsplus verifies that
+ // passing too many args isn't fatal; it works -- but
+ // would be nice to notice the warning too.
+ }
+ }
+ }
+ }
+
+ template<> template<>
+ void object::test<21>()
+ {
+ set_test_name("verify that passing LLSD() to const char* sends NULL");
+
+ ensure_equals("Vars::cp init", v.cp, "");
+ work("methodna_map_mdft", LLSDMap("cp", LLSD()));
+ ensure_equals("passing LLSD()", v.cp, "NULL");
+ work("methodna_map_mdft", LLSDMap("cp", ""));
+ ensure_equals("passing \"\"", v.cp, "''");
+ work("methodna_map_mdft", LLSDMap("cp", "non-NULL"));
+ ensure_equals("passing \"non-NULL\"", v.cp, "'non-NULL'");
+ }
+
+ template<> template<>
+ void object::test<22>()
+ {
+ set_test_name("call map-style functions with (full | oversized) (arrays | maps)");
+ const char binary[] = "\x99\x88\x77\x66\x55";
+ LLSD array_full(LLSDMap
+ ("a", LLSDArray(false)(255)(98.6)(1024.5)("pointer"))
+ ("b", LLSDArray("object")(LLUUID::generateNewID())(LLDate::now())(LLURI("http://wiki.lindenlab.com/wiki"))(LLSD::Binary(boost::begin(binary), boost::end(binary)))));
+ LLSD array_overfull(array_full);
+ foreach(LLSD::String a, ab)
+ {
+ array_overfull[a].append("bogus");
+ }
+ cout << "array_full: " << array_full << "\narray_overfull: " << array_overfull << std::endl;
+ // We rather hope that LLDate::now() will generate a timestamp
+ // distinct from the one it generated in the constructor, moments ago.
+ ensure_not_equals("Timestamps too close",
+ array_full["b"][2].asDate(), dft_array_full["b"][2].asDate());
+ // We /insist/ that LLUUID::generateNewID() do so.
+ ensure_not_equals("UUID collision",
+ array_full["b"][1].asUUID(), dft_array_full["b"][1].asUUID());
+ LLSD map_full, map_overfull;
+ foreach(LLSD::String a, ab)
+ {
+ map_full[a] = zipmap(params[a], array_full[a]);
+ map_overfull[a] = map_full[a];
+ map_overfull[a]["extra"] = "ignore";
+ }
+ cout << "map_full: " << map_full << "\nmap_overfull: " << map_overfull << std::endl;
+ LLSD expect(map_full);
+ // Twiddle the const char* param.
+ expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
+ // Another adjustment. For each data type, we're trying to distinguish
+ // three values: the Vars member's initial value (member wasn't
+ // stored; control never reached the set function), the registered
+ // default param value from dft_array_full, and the array_full value
+ // in this test. But bool can only distinguish two values. In this
+ // case, we want to differentiate the local array_full value from the
+ // dft_array_full value, so we use 'false'. However, that means
+ // Vars::inspect() doesn't differentiate it from the initial value,
+ // so won't bother returning it. Predict that behavior to match the
+ // LLSD values.
+ expect["a"].erase("b");
+ cout << "expect: " << expect << std::endl;
+ // For this test, calling functions registered with different sets of
+ // parameter defaults should make NO DIFFERENCE WHATSOEVER. Every call
+ // should pass all params.
+ LLSD names(LLSDMap
+ ("a", LLSDArray
+ ("freena_map_allreq") ("smethodna_map_allreq") ("methodna_map_allreq")
+ ("freena_map_leftreq")("smethodna_map_leftreq")("methodna_map_leftreq")
+ ("freena_map_skipreq")("smethodna_map_skipreq")("methodna_map_skipreq")
+ ("freena_map_adft") ("smethodna_map_adft") ("methodna_map_adft")
+ ("freena_map_mdft") ("smethodna_map_mdft") ("methodna_map_mdft"))
+ ("b", LLSDArray
+ ("freenb_map_allreq") ("smethodnb_map_allreq") ("methodnb_map_allreq")
+ ("freenb_map_leftreq")("smethodnb_map_leftreq")("methodnb_map_leftreq")
+ ("freenb_map_skipreq")("smethodnb_map_skipreq")("methodnb_map_skipreq")
+ ("freenb_map_adft") ("smethodnb_map_adft") ("methodnb_map_adft")
+ ("freenb_map_mdft") ("smethodnb_map_mdft") ("methodnb_map_mdft")));
+ // Treat (full | overfull) (array | map) the same.
+ LLSD argssets(LLSDArray(array_full)(array_overfull)(map_full)(map_overfull));
+ foreach(const LLSD& args, inArray(argssets))
+ {
+ foreach(LLSD::String a, ab)
+ {
+ foreach(LLSD::String name, inArray(names[a]))
+ {
+ // Reset the Vars instance
+ Vars* vars(varsfor(name));
+ *vars = Vars();
+ work(name, args[a]);
+ ensure_llsd(STRINGIZE(name << ": expect[\"" << a << "\"] mismatch"),
+ vars->inspect(), expect[a], 7); // 7 bits, 2 decimal digits
+ // intercept LL_WARNS for the two overfull cases?
+ }
+ }
+ }
+ }
+} // namespace tut
diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp
index 835664c60f..c6bfa50b40 100644
--- a/indra/llimage/llimagedimensionsinfo.cpp
+++ b/indra/llimage/llimagedimensionsinfo.cpp
@@ -73,9 +73,28 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
bool LLImageDimensionsInfo::getImageDimensionsBmp()
{
- const S32 BMP_FILE_HEADER_SIZE = 14;
+ // Make sure the file is long enough.
+ const S32 DATA_LEN = 26; // BMP header (14) + DIB header size (4) + width (4) + height (4)
+ if (!checkFileLength(DATA_LEN))
+ {
+ llwarns << "Premature end of file" << llendl;
+ return false;
+ }
+
+ // Read BMP signature.
+ U8 signature[2];
+ mInfile.read((void*)signature, sizeof(signature)/sizeof(signature[0]));
+
+ // Make sure this is actually a BMP file.
+ // We only support Windows bitmaps (BM), according to LLImageBMP::updateData().
+ if (signature[0] != 'B' || signature[1] != 'M')
+ {
+ llwarns << "Not a BMP" << llendl;
+ return false;
+ }
- mInfile.seek(APR_CUR,BMP_FILE_HEADER_SIZE+4);
+ // Read image dimensions.
+ mInfile.seek(APR_CUR, 16);
mWidth = read_reverse_s32();
mHeight = read_reverse_s32();
@@ -86,6 +105,14 @@ bool LLImageDimensionsInfo::getImageDimensionsTga()
{
const S32 TGA_FILE_HEADER_SIZE = 12;
+ // Make sure the file is long enough.
+ if (!checkFileLength(TGA_FILE_HEADER_SIZE + 1 /* width */ + 1 /* height */))
+ {
+ llwarns << "Premature end of file" << llendl;
+ return false;
+ }
+
+ // *TODO: Detect non-TGA files somehow.
mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
mWidth = read_byte() | read_byte() << 8;
mHeight = read_byte() | read_byte() << 8;
@@ -95,9 +122,29 @@ bool LLImageDimensionsInfo::getImageDimensionsTga()
bool LLImageDimensionsInfo::getImageDimensionsPng()
{
- const S32 PNG_FILE_MARKER_SIZE = 8;
+ const S32 PNG_MAGIC_SIZE = 8;
+
+ // Make sure the file is long enough.
+ if (!checkFileLength(PNG_MAGIC_SIZE + 8 + sizeof(S32) * 2 /* width, height */))
+ {
+ llwarns << "Premature end of file" << llendl;
+ return false;
+ }
- mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/);
+ // Read PNG signature.
+ const U8 png_magic[PNG_MAGIC_SIZE] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
+ U8 signature[PNG_MAGIC_SIZE];
+ mInfile.read((void*)signature, PNG_MAGIC_SIZE);
+
+ // Make sure it's a PNG file.
+ if (memcmp(signature, png_magic, PNG_MAGIC_SIZE) != 0)
+ {
+ llwarns << "Not a PNG" << llendl;
+ return false;
+ }
+
+ // Read image dimensions.
+ mInfile.seek(APR_CUR, 8 /* chunk length + chunk type */);
mWidth = read_s32();
mHeight = read_s32();
@@ -122,6 +169,24 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
setLastError("Unable to open file for reading", mSrcFilename);
return false;
}
+
+ /* Make sure this is a JPEG file. */
+ const size_t JPEG_MAGIC_SIZE = 2;
+ const uint8_t jpeg_magic[JPEG_MAGIC_SIZE] = {0xFF, 0xD8};
+ uint8_t signature[JPEG_MAGIC_SIZE];
+
+ if (fread(signature, sizeof(signature), 1, fp) != 1)
+ {
+ llwarns << "Premature end of file" << llendl;
+ return false;
+ }
+ if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0)
+ {
+ llwarns << "Not a JPEG" << llendl;
+ return false;
+ }
+ fseek(fp, 0, SEEK_SET); // go back to start of the file
+
/* Init jpeg */
jpeg_error_mgr jerr;
jpeg_decompress_struct cinfo;
@@ -145,3 +210,13 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
return !sJpegErrorEncountered;
}
+bool LLImageDimensionsInfo::checkFileLength(S32 min_len)
+{
+ // Make sure the file is not shorter than min_len bytes.
+ // so that we don't have to check value returned by each read() or seek().
+ char* buf = new char[min_len];
+ int nread = mInfile.read(buf, min_len);
+ delete[] buf;
+ mInfile.seek(APR_SET, 0);
+ return nread == min_len;
+}
diff --git a/indra/llimage/llimagedimensionsinfo.h b/indra/llimage/llimagedimensionsinfo.h
index 5384faf3f4..382fdb2a0e 100644
--- a/indra/llimage/llimagedimensionsinfo.h
+++ b/indra/llimage/llimagedimensionsinfo.h
@@ -119,6 +119,9 @@ protected:
return read_byte() << 8 | read_byte();
}
+ /// Check if the file is not shorter than min_len bytes.
+ bool checkFileLength(S32 min_len);
+
protected:
LLAPRFile mInfile ;
std::string mSrcFilename;
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 26a20cede8..2103216536 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -144,8 +144,10 @@ void LLPluginClassMedia::reset()
mStatusText.clear();
mProgressPercent = 0;
mClickURL.clear();
+ mClickNavType.clear();
mClickTarget.clear();
mClickUUID.clear();
+ mStatusCode = 0;
// media_time class
mCurrentTime = 0.0f;
@@ -1024,9 +1026,15 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
else if(message_name == "click_nofollow")
{
mClickURL = message.getValue("uri");
+ mClickNavType = message.getValue("nav_type");
mClickTarget.clear();
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
}
+ else if(message_name == "navigate_error_page")
+ {
+ mStatusCode = message.getValueS32("status_code");
+ mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
+ }
else if(message_name == "cookie_set")
{
if(mOwner)
@@ -1192,16 +1200,6 @@ void LLPluginClassMedia::browse_back()
sendMessage(message);
}
-void LLPluginClassMedia::set_status_redirect(int code, const std::string &url)
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect");
-
- message.setValueS32("code", code);
- message.setValue("url", url);
-
- sendMessage(message);
-}
-
void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 618e928a08..cf8d8b26b9 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -199,7 +199,6 @@ public:
void browse_reload(bool ignore_cache = false);
void browse_forward();
void browse_back();
- void set_status_redirect(int code, const std::string &url);
void setBrowserUserAgent(const std::string& user_agent);
void proxyWindowOpened(const std::string &target, const std::string &uuid);
void proxyWindowClosed(const std::string &uuid);
@@ -227,11 +226,17 @@ public:
// This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW
std::string getClickURL() const { return mClickURL; };
+ // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW
+ std::string getClickNavType() const { return mClickNavType; };
+
// This is valid after MEDIA_EVENT_CLICK_LINK_HREF
std::string getClickTarget() const { return mClickTarget; };
// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
std::string getClickUUID() const { return mClickUUID; };
+
+ // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE
+ S32 getStatusCode() const { return mStatusCode; };
// These are valid during MEDIA_EVENT_GEOMETRY_CHANGE
S32 getGeometryX() const { return mGeometryX; };
@@ -378,12 +383,14 @@ protected:
int mProgressPercent;
std::string mLocation;
std::string mClickURL;
+ std::string mClickNavType;
std::string mClickTarget;
std::string mClickUUID;
S32 mGeometryX;
S32 mGeometryY;
S32 mGeometryWidth;
S32 mGeometryHeight;
+ S32 mStatusCode;
std::string mAuthURL;
std::string mAuthRealm;
std::string mHoverText;
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index 42e93cc6d7..5a4fb1ce90 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -52,12 +52,13 @@ public:
MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text
MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically <title> tag)
MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc)
+ MEDIA_EVENT_NAVIGATE_ERROR_PAGE, // browser navigated to a page that resulted in an HTTP error
MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are
MEDIA_EVENT_CLICK_LINK_NOFOLLOW,
MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit)
MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file
MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface)
-
+
MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch
MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index b508705759..99a1e5c826 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -57,9 +57,12 @@
BOOL gDebugSession = FALSE;
BOOL gDebugGL = FALSE;
BOOL gClothRipple = FALSE;
-BOOL gNoRender = FALSE;
+BOOL gHeadlessClient = FALSE;
BOOL gGLActive = FALSE;
+static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
+static const std::string HEADLESS_RENDERER_STRING("Headless");
+static const std::string HEADLESS_VERSION_STRING("1.0");
std::ofstream gFailLog;
@@ -551,9 +554,19 @@ void LLGLManager::setToDebugGPU()
void LLGLManager::getGLInfo(LLSD& info)
{
- info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
- info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
- info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
+ if (gHeadlessClient)
+ {
+ info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING;
+ info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING;
+ info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING;
+ return;
+ }
+ else
+ {
+ info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
+ info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
+ info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
+ }
#if !LL_MESA_HEADLESS
std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts);
@@ -569,14 +582,22 @@ void LLGLManager::getGLInfo(LLSD& info)
std::string LLGLManager::getGLInfoString()
{
std::string info_str;
- std::string all_exts, line;
- info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
- info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
- info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
+ if (gHeadlessClient)
+ {
+ info_str += std::string("GL_VENDOR ") + HEADLESS_VENDOR_STRING + std::string("\n");
+ info_str += std::string("GL_RENDERER ") + HEADLESS_RENDERER_STRING + std::string("\n");
+ info_str += std::string("GL_VERSION ") + HEADLESS_VERSION_STRING + std::string("\n");
+ }
+ else
+ {
+ info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
+ info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
+ info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
+ }
#if !LL_MESA_HEADLESS
- all_exts = (const char *)gGLHExts.mSysExts;
+ std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
LLStringUtil::replaceChar(all_exts, ' ', '\n');
info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n");
#endif
@@ -586,15 +607,21 @@ std::string LLGLManager::getGLInfoString()
void LLGLManager::printGLInfoString()
{
- std::string info_str;
- std::string all_exts, line;
-
- LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
- LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
- LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
+ if (gHeadlessClient)
+ {
+ LL_INFOS("RenderInit") << "GL_VENDOR: " << HEADLESS_VENDOR_STRING << LL_ENDL;
+ LL_INFOS("RenderInit") << "GL_RENDERER: " << HEADLESS_RENDERER_STRING << LL_ENDL;
+ LL_INFOS("RenderInit") << "GL_VERSION: " << HEADLESS_VERSION_STRING << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("RenderInit") << "GL_VENDOR: " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
+ LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
+ LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
+ }
#if !LL_MESA_HEADLESS
- all_exts = std::string(gGLHExts.mSysExts);
+ std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts));
LLStringUtil::replaceChar(all_exts, ' ', '\n');
LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL;
#endif
@@ -603,7 +630,14 @@ void LLGLManager::printGLInfoString()
std::string LLGLManager::getRawGLString()
{
std::string gl_string;
- gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
+ if (gHeadlessClient)
+ {
+ gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING;
+ }
+ else
+ {
+ gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
+ }
return gl_string;
}
@@ -627,42 +661,42 @@ void LLGLManager::initExtensions()
mHasMultitexture = TRUE;
# else
mHasMultitexture = FALSE;
-# endif
+# endif // GL_ARB_multitexture
# ifdef GL_ARB_texture_env_combine
mHasARBEnvCombine = TRUE;
# else
mHasARBEnvCombine = FALSE;
-# endif
+# endif // GL_ARB_texture_env_combine
# ifdef GL_ARB_texture_compression
mHasCompressedTextures = TRUE;
# else
mHasCompressedTextures = FALSE;
-# endif
+# endif // GL_ARB_texture_compression
# ifdef GL_ARB_vertex_buffer_object
mHasVertexBufferObject = TRUE;
# else
mHasVertexBufferObject = FALSE;
-# endif
+# endif // GL_ARB_vertex_buffer_object
# ifdef GL_EXT_framebuffer_object
mHasFramebufferObject = TRUE;
# else
mHasFramebufferObject = FALSE;
-# endif
+# endif // GL_EXT_framebuffer_object
# ifdef GL_ARB_draw_buffers
mHasDrawBuffers = TRUE;
#else
mHasDrawBuffers = FALSE;
-# endif
+# endif // GL_ARB_draw_buffers
# if defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
mHasDepthClamp = TRUE;
#else
mHasDepthClamp = FALSE;
-#endif
+#endif // defined(GL_NV_depth_clamp) || defined(GL_ARB_depth_clamp)
# if GL_EXT_blend_func_separate
mHasBlendFuncSeparate = TRUE;
#else
mHasBlendFuncSeparate = FALSE;
-# endif
+# endif // GL_EXT_blend_func_separate
mHasMipMapGeneration = FALSE;
mHasSeparateSpecularColor = FALSE;
mHasAnisotropic = FALSE;
@@ -1162,7 +1196,7 @@ void assert_glerror()
}
}
- if (!gNoRender && gDebugGL)
+ if (gDebugGL)
{
do_assert_glerror();
}
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 43992d51cb..c77d85ba2b 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -419,7 +419,7 @@ void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals
void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
extern BOOL gClothRipple;
-extern BOOL gNoRender;
+extern BOOL gHeadlessClient;
extern BOOL gGLActive;
// Deal with changing glext.h definitions for newer SDK versions, specifically
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index dfd72d13b0..d408077c68 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -967,12 +967,14 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
}
if (mTexName == 0)
{
- llwarns << "Setting subimage on image without GL texture" << llendl;
+ // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18
+ //llwarns << "Setting subimage on image without GL texture" << llendl;
return FALSE;
}
if (datap == NULL)
{
- llwarns << "Setting subimage on image with NULL datap" << llendl;
+ // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18
+ //llwarns << "Setting subimage on image with NULL datap" << llendl;
return FALSE;
}
@@ -1100,6 +1102,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
//the texture is assiciate with some image by calling glTexImage outside LLImageGL
BOOL LLImageGL::createGLTexture()
{
+ if (gHeadlessClient) return FALSE;
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -1128,6 +1131,7 @@ BOOL LLImageGL::createGLTexture()
BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
{
+ if (gHeadlessClient) return FALSE;
if (gGLManager.mIsDisabled)
{
llwarns << "Trying to create a texture while GL is disabled!" << llendl;
diff --git a/indra/llui/llfloaterreglistener.cpp b/indra/llui/llfloaterreglistener.cpp
index 821d4543ae..7525b8cab3 100644
--- a/indra/llui/llfloaterreglistener.cpp
+++ b/indra/llui/llfloaterreglistener.cpp
@@ -60,6 +60,11 @@ LLFloaterRegListener::LLFloaterRegListener():
"Ask to toggle the state of the floater specified in [\"name\"]",
&LLFloaterRegListener::toggleInstance,
requiredName);
+ add("instanceVisible",
+ "Return on [\"reply\"] an event whose [\"visible\"] indicates the visibility "
+ "of the floater specified in [\"name\"]",
+ &LLFloaterRegListener::instanceVisible,
+ requiredName);
LLSD requiredNameButton;
requiredNameButton["name"] = LLSD();
requiredNameButton["button"] = LLSD();
@@ -71,9 +76,7 @@ LLFloaterRegListener::LLFloaterRegListener():
void LLFloaterRegListener::getBuildMap(const LLSD& event) const
{
- // Honor the "reqid" convention by echoing event["reqid"] in our reply packet.
- LLReqID reqID(event);
- LLSD reply(reqID.makeResponse());
+ LLSD reply;
// Build an LLSD map that mirrors sBuildMap. Since we have no good way to
// represent a C++ callable in LLSD, the only part of BuildData we can
// store is the filename. For each LLSD map entry, it would be more
@@ -86,7 +89,7 @@ void LLFloaterRegListener::getBuildMap(const LLSD& event) const
reply[mi->first] = mi->second.mFile;
}
// Send the reply to the LLEventPump named in event["reply"].
- LLEventPumps::instance().obtain(event["reply"]).post(reply);
+ sendReply(reply, event);
}
void LLFloaterRegListener::showInstance(const LLSD& event) const
@@ -104,6 +107,12 @@ void LLFloaterRegListener::toggleInstance(const LLSD& event) const
LLFloaterReg::toggleInstance(event["name"], event["key"]);
}
+void LLFloaterRegListener::instanceVisible(const LLSD& event) const
+{
+ sendReply(LLSDMap("visible", LLFloaterReg::instanceVisible(event["name"], event["key"])),
+ event);
+}
+
void LLFloaterRegListener::clickButton(const LLSD& event) const
{
// If the caller requests a reply, build the reply.
diff --git a/indra/llui/llfloaterreglistener.h b/indra/llui/llfloaterreglistener.h
index 586656667c..24311a2dfa 100644
--- a/indra/llui/llfloaterreglistener.h
+++ b/indra/llui/llfloaterreglistener.h
@@ -47,6 +47,7 @@ private:
void showInstance(const LLSD& event) const;
void hideInstance(const LLSD& event) const;
void toggleInstance(const LLSD& event) const;
+ void instanceVisible(const LLSD& event) const;
void clickButton(const LLSD& event) const;
};
diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h
index e9bdab2d47..669e126266 100644
--- a/indra/llui/lliconctrl.h
+++ b/indra/llui/lliconctrl.h
@@ -69,6 +69,7 @@ public:
void setColor(const LLColor4& color) { mColor = color; }
void setImage(LLPointer<LLUIImage> image) { mImagep = image; }
+ const LLPointer<LLUIImage> getImage() { return mImagep; }
private:
void setIconImageDrawSize() ;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 8c8c38415e..0196080d90 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -2294,3 +2294,8 @@ void LLLineEditor::setContextMenu(LLContextMenu* new_context_menu)
else
mContextMenuHandle.markDead();
}
+
+void LLLineEditor::setFont(const LLFontGL* font)
+{
+ mGLFont = font;
+}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 723423a5b9..7b5fa218f2 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -201,6 +201,7 @@ public:
const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
const LLFontGL* getFont() const { return mGLFont; }
+ void setFont(const LLFontGL* font);
void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(BOOL b) { mIgnoreTab = b; }
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index f0374de98f..8de9c769e2 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3105,9 +3105,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
CURSOR_HEIGHT + MOUSE_CURSOR_PADDING * 2);
menu->translateIntoRectWithExclusion( menu_region_rect, mouse_rect, FALSE );
menu->getParent()->sendChildToFront(menu);
-
-
-
}
///============================================================================
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 333513d7d7..2060e5f9cf 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -157,6 +157,7 @@ LLTextBase::Params::Params()
read_only("read_only", false),
v_pad("v_pad", 0),
h_pad("h_pad", 0),
+ clip("clip", true),
clip_partial("clip_partial", true),
line_spacing("line_spacing"),
max_text_length("max_length", 255),
@@ -199,6 +200,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mVAlign(p.font_valign),
mLineSpacingMult(p.line_spacing.multiple),
mLineSpacingPixels(p.line_spacing.pixels),
+ mClip(p.clip),
mClipPartial(p.clip_partial && !p.allow_scroll),
mTrackEnd( p.track_end ),
mScrollIndex(-1),
@@ -334,7 +336,7 @@ void LLTextBase::drawSelectionBackground()
// binary search for line that starts before top of visible buffer
line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mTop, compare_bottom());
- line_list_t::const_iterator end_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
+ line_list_t::const_iterator end_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), content_display_rect.mBottom, compare_top());
bool done = false;
@@ -512,7 +514,6 @@ void LLTextBase::drawText()
selection_right = llmax( mSelectionStart, mSelectionEnd );
}
- LLRect scrolled_view_rect = getVisibleDocumentRect();
std::pair<S32, S32> line_range = getVisibleLines(mClipPartial);
S32 first_line = line_range.first;
S32 last_line = line_range.second;
@@ -545,10 +546,10 @@ void LLTextBase::drawText()
line_end = next_start;
}
- LLRect text_rect(line.mRect.mLeft + mVisibleTextRect.mLeft - scrolled_view_rect.mLeft,
- line.mRect.mTop - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom,
- llmin(mDocumentView->getRect().getWidth(), line.mRect.mRight) - scrolled_view_rect.mLeft,
- line.mRect.mBottom - scrolled_view_rect.mBottom + mVisibleTextRect.mBottom);
+ LLRect text_rect(line.mRect);
+ text_rect.mRight = llmin(mDocumentView->getRect().getWidth(), text_rect.mRight); // clamp right edge to document extents
+ text_rect.translate(mVisibleTextRect.mLeft, mVisibleTextRect.mBottom); // translate into display region of text widget
+ text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position
// draw a single line of text
S32 seg_start = line_start;
@@ -993,14 +994,28 @@ void LLTextBase::draw()
updateScrollFromCursor();
}
- LLRect doc_rect;
+ LLRect text_rect;
if (mScroller)
{
- mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &doc_rect, this);
+ mScroller->localRectToOtherView(mScroller->getContentWindowRect(), &text_rect, this);
}
else
{
- doc_rect = getLocalRect();
+ LLRect visible_lines_rect;
+ std::pair<S32, S32> line_range = getVisibleLines(mClipPartial);
+ for (S32 i = line_range.first; i < line_range.second; i++)
+ {
+ if (visible_lines_rect.isEmpty())
+ {
+ visible_lines_rect = mLineInfoList[i].mRect;
+ }
+ else
+ {
+ visible_lines_rect.unionWith(mLineInfoList[i].mRect);
+ }
+ }
+ text_rect = visible_lines_rect;
+ text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom);
}
if (mBGVisible)
@@ -1010,28 +1025,37 @@ void LLTextBase::draw()
LLRect bg_rect = mVisibleTextRect;
if (mScroller)
{
- bg_rect.intersectWith(doc_rect);
+ bg_rect.intersectWith(text_rect);
}
LLColor4 bg_color = mReadOnly
? mReadOnlyBgColor.get()
: hasFocus()
? mFocusBgColor.get()
: mWriteableBgColor.get();
- gl_rect_2d(doc_rect, bg_color % alpha, TRUE);
+ gl_rect_2d(text_rect, bg_color % alpha, TRUE);
}
- // draw document view
- LLUICtrl::draw();
-
- {
- // only clip if we support scrolling...
- // since convention is that text boxes never vertically truncate their contents
- // regardless of rect bounds
- LLLocalClipRect clip(doc_rect, mScroller != NULL);
+ bool should_clip = mClip || mScroller != NULL;
+ { LLLocalClipRect clip(text_rect, should_clip);
+
+ // draw document view
+ if (mScroller)
+ {
+ drawChild(mScroller);
+ }
+ else
+ {
+ drawChild(mDocumentView);
+ }
+
drawSelectionBackground();
drawText();
drawCursor();
}
+
+ mDocumentView->setVisible(FALSE);
+ LLUICtrl::draw();
+ mDocumentView->setVisible(TRUE);
}
@@ -1415,7 +1439,7 @@ S32 LLTextBase::getFirstVisibleLine() const
return iter - mLineInfoList.begin();
}
-std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible)
+std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible)
{
LLRect visible_region = getVisibleDocumentRect();
line_list_t::const_iterator first_iter;
@@ -1424,14 +1448,14 @@ std::pair<S32, S32> LLTextBase::getVisibleLines(bool fully_visible)
// make sure we have an up-to-date mLineInfoList
reflow();
- if (fully_visible)
+ if (require_fully_visible)
{
first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_top());
- last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom());
+ last_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_bottom());
}
else
{
- first_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
+ first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top());
}
return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin());
@@ -2404,14 +2428,41 @@ LLRect LLTextBase::getVisibleDocumentRect() const
{
return mScroller->getVisibleContentRect();
}
- else
+ else if (mClip)
{
- // entire document rect is visible when not scrolling
+ LLRect visible_text_rect = getVisibleTextRect();
+ LLRect doc_rect = mDocumentView->getRect();
+ visible_text_rect.translate(-doc_rect.mLeft, -doc_rect.mBottom);
+
+ // reject partially visible lines
+ LLRect visible_lines_rect;
+ for (line_list_t::const_iterator it = mLineInfoList.begin(), end_it = mLineInfoList.end();
+ it != end_it;
+ ++it)
+ {
+ bool line_visible = mClipPartial ? visible_text_rect.contains(it->mRect) : visible_text_rect.overlaps(it->mRect);
+ if (line_visible)
+ {
+ if (visible_lines_rect.isEmpty())
+ {
+ visible_lines_rect = it->mRect;
+ }
+ else
+ {
+ visible_lines_rect.unionWith(it->mRect);
+ }
+ }
+ }
+ return visible_lines_rect;
+ }
+ else
+ { // entire document rect is visible
// but offset according to height of widget
+
LLRect doc_rect = mDocumentView->getLocalRect();
doc_rect.mLeft -= mDocumentView->getRect().mLeft;
// adjust for height of text above widget baseline
- doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight();
+ doc_rect.mBottom = llmin(0, doc_rect.getHeight() - mVisibleTextRect.getHeight());
return doc_rect;
}
}
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index aafcf8ceb0..7d545a1ba6 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -265,6 +265,7 @@ public:
use_ellipses,
parse_urls,
parse_highlights,
+ clip,
clip_partial;
Optional<S32> v_pad,
@@ -338,7 +339,7 @@ public:
void addDocumentChild(LLView* view);
void removeDocumentChild(LLView* view);
const LLView* getDocumentView() const { return mDocumentView; }
- LLRect getVisibleTextRect() { return mVisibleTextRect; }
+ LLRect getVisibleTextRect() const { return mVisibleTextRect; }
LLRect getTextBoundingRect();
LLRect getVisibleDocumentRect() const;
@@ -552,6 +553,7 @@ protected:
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
bool mReadOnly;
bool mBGVisible; // render background?
+ bool mClip; // clip text to widget rect
bool mClipPartial; // false if we show lines that are partially inside bounding rect
bool mPlainText; // didn't use Image or Icon segments
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index c300fe55d9..87669574c2 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -61,6 +61,8 @@
// for XUIParse
#include "llquaternion.h"
#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/find_iterator.hpp>
+#include <boost/algorithm/string/finder.hpp>
//
// Globals
@@ -2020,6 +2022,53 @@ void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y)
view->translateIntoRectWithExclusion( virtual_window_rect, mouse_rect, FALSE );
}
+LLView* LLUI::resolvePath(LLView* context, const std::string& path)
+{
+ // Nothing about resolvePath() should require non-const LLView*. If caller
+ // wants non-const, call the const flavor and then cast away const-ness.
+ return const_cast<LLView*>(resolvePath(const_cast<const LLView*>(context), path));
+}
+
+const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
+{
+ // Create an iterator over slash-separated parts of 'path'. Dereferencing
+ // this iterator returns an iterator_range over the substring. Unlike
+ // LLStringUtil::getTokens(), this split_iterator doesn't combine adjacent
+ // delimiters: leading/trailing slash produces an empty substring, double
+ // slash produces an empty substring. That's what we need.
+ boost::split_iterator<std::string::const_iterator> ti(path, boost::first_finder("/")), tend;
+
+ if (ti == tend)
+ {
+ // 'path' is completely empty, no navigation
+ return context;
+ }
+
+ // leading / means "start at root"
+ if (ti->empty())
+ {
+ context = getRootView();
+ ++ti;
+ }
+
+ bool recurse = false;
+ for (; ti != tend && context; ++ti)
+ {
+ if (ti->empty())
+ {
+ recurse = true;
+ }
+ else
+ {
+ std::string part(ti->begin(), ti->end());
+ context = context->findChildView(part, recurse);
+ recurse = false;
+ }
+ }
+
+ return context;
+}
+
// LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 62d10df8b2..50cb9e6632 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -185,6 +185,33 @@ public:
//helper functions (should probably move free standing rendering helper functions here)
static LLView* getRootView() { return sRootView; }
static void setRootView(LLView* view) { sRootView = view; }
+ /**
+ * Walk the LLView tree to resolve a path
+ * Paths can be discovered using Develop > XUI > Show XUI Paths
+ *
+ * A leading "/" indicates the root of the tree is the starting
+ * position of the search, (otherwise the context node is used)
+ *
+ * Adjacent "//" mean that the next level of the search is done
+ * recursively ("descendant" rather than "child").
+ *
+ * Return values: If no match is found, NULL is returned,
+ * otherwise the matching LLView* is returned.
+ *
+ * Examples:
+ *
+ * "/" -> return the root view
+ * "/foo" -> find "foo" as a direct child of the root
+ * "foo" -> find "foo" as a direct child of the context node
+ * "//foo" -> find the first "foo" child anywhere in the tree
+ * "/foo/bar" -> find "foo" as direct child of the root, and
+ * "bar" as a direct child of "foo"
+ * "//foo//bar/baz" -> find the first "foo" anywhere in the
+ * tree, the first "bar" anywhere under it, and "baz"
+ * as a direct child of that
+ */
+ static const LLView* resolvePath(const LLView* context, const std::string& path);
+ static LLView* resolvePath(LLView* context, const std::string& path);
static std::string locateSkin(const std::string& filename);
static void setMousePositionScreen(S32 x, S32 y);
static void getMousePositionScreen(S32 *x, S32 *y);
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index 9d174ef1cd..3d89867bc1 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -35,16 +35,20 @@ include_directories(
set(llwindow_SOURCE_FILES
llkeyboard.cpp
+ llkeyboardheadless.cpp
llwindowheadless.cpp
llwindowcallbacks.cpp
+ llwindowlistener.cpp
)
set(llwindow_HEADER_FILES
CMakeLists.txt
llkeyboard.h
+ llkeyboardheadless.h
llwindowheadless.h
llwindowcallbacks.h
+ llwindowlistener.h
)
set(viewer_SOURCE_FILES
diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp
new file mode 100644
index 0000000000..4dfaaed4e1
--- /dev/null
+++ b/indra/llwindow/llkeyboardheadless.cpp
@@ -0,0 +1,50 @@
+/**
+ * @file llkeyboardheadless.cpp
+ * @brief Handler for assignable key bindings
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+#include "llkeyboardheadless.h"
+#include "llwindowcallbacks.h"
+
+LLKeyboardHeadless::LLKeyboardHeadless()
+{ }
+
+void LLKeyboardHeadless::resetMaskKeys()
+{ }
+
+
+BOOL LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask)
+{ return FALSE; }
+
+
+BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask)
+{ return FALSE; }
+
+MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event)
+{ return MASK_NONE; }
+
+void LLKeyboardHeadless::scanKeyboard()
+{ }
+
diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h
new file mode 100644
index 0000000000..4e666f8ce8
--- /dev/null
+++ b/indra/llwindow/llkeyboardheadless.h
@@ -0,0 +1,45 @@
+/**
+ * @file llkeyboardheadless.h
+ * @brief Handler for assignable key bindings
+ *
+ * $LicenseInfo:firstyear=2004&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_LLKEYBOARDHEADLESS_H
+#define LL_LLKEYBOARDHEADLESS_H
+
+#include "llkeyboard.h"
+
+class LLKeyboardHeadless : public LLKeyboard
+{
+public:
+ LLKeyboardHeadless();
+ /*virtual*/ ~LLKeyboardHeadless() {};
+
+ /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask);
+ /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask);
+ /*virtual*/ void resetMaskKeys();
+ /*virtual*/ MASK currentMask(BOOL for_mouse_event);
+ /*virtual*/ void scanKeyboard();
+};
+
+#endif
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 072f694c24..71a5df910d 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -41,6 +41,8 @@
#include "llkeyboard.h"
#include "linked_lists.h"
#include "llwindowcallbacks.h"
+#include "llwindowlistener.h"
+#include <boost/lambda/core.hpp>
//
@@ -115,10 +117,19 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags)
mHideCursorPermanent(FALSE),
mFlags(flags),
mHighSurrogate(0)
-{ }
+{
+ // gKeyboard is still NULL, so it doesn't do LLWindowListener any good to
+ // pass its value right now. Instead, pass it a nullary function that
+ // will, when we later need it, return the value of gKeyboard.
+ // boost::lambda::var() constructs such a functor on the fly.
+ mListener = new LLWindowListener(callbacks, boost::lambda::var(gKeyboard));
+}
LLWindow::~LLWindow()
-{ }
+{
+ delete mListener;
+ mListener = NULL;
+}
//virtual
BOOL LLWindow::isValid()
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index e8a86a1880..6bdc01ae88 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -36,6 +36,7 @@
class LLSplashScreen;
class LLPreeditor;
class LLWindowCallbacks;
+class LLWindowListener;
// Refer to llwindow_test in test/common/llwindow for usage example
@@ -188,6 +189,7 @@ protected:
BOOL mHideCursorPermanent;
U32 mFlags;
U16 mHighSurrogate;
+ LLWindowListener* mListener;
// Handle a UTF-16 encoding unit received from keyboard.
// Converting the series of UTF-16 encoding units to UTF-32 data,
diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp
index 35398f1c09..e6e6bc67ff 100644
--- a/indra/llwindow/llwindowheadless.cpp
+++ b/indra/llwindow/llwindowheadless.cpp
@@ -28,6 +28,7 @@
#include "indra_constants.h"
#include "llwindowheadless.h"
+#include "llkeyboardheadless.h"
//
// LLWindowHeadless
@@ -37,6 +38,9 @@ LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::stri
BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth)
: LLWindow(callbacks, fullscreen, flags)
{
+ // Initialize a headless keyboard.
+ gKeyboard = new LLKeyboardHeadless();
+ gKeyboard->setCallbacks(callbacks);
}
diff --git a/indra/llwindow/llwindowlistener.cpp b/indra/llwindow/llwindowlistener.cpp
new file mode 100644
index 0000000000..91b99d83c6
--- /dev/null
+++ b/indra/llwindow/llwindowlistener.cpp
@@ -0,0 +1,307 @@
+/**
+ * @file llwindowlistener.cpp
+ * @brief EventAPI interface for injecting input into LLWindow
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llwindowlistener.h"
+
+#include "llcoord.h"
+#include "llkeyboard.h"
+#include "llwindowcallbacks.h"
+#include <map>
+
+LLWindowListener::LLWindowListener(LLWindowCallbacks *window, const KeyboardGetter& kbgetter)
+ : LLEventAPI("LLWindow", "Inject input events into the LLWindow instance"),
+ mWindow(window),
+ mKbGetter(kbgetter)
+{
+ std::string keySomething =
+ "Given [\"keysym\"], [\"keycode\"] or [\"char\"], inject the specified ";
+ std::string keyExplain =
+ "(integer keycode values, or keysym \"XXXX\" from any KEY_XXXX, in\n"
+ "http://hg.secondlife.com/viewer-development/src/tip/indra/llcommon/indra_constants.h )";
+ std::string mask =
+ "Specify optional [\"mask\"] as an array containing any of \"CONTROL\", \"ALT\",\n"
+ "\"SHIFT\" or \"MAC_CONTROL\"; the corresponding modifier bits will be combined\n"
+ "to form the mask used with the event.";
+
+ std::string mouseSomething =
+ "Given [\"button\"], [\"x\"] and [\"y\"], inject the given mouse ";
+ std::string mouseExplain =
+ "(button values \"LEFT\", \"MIDDLE\", \"RIGHT\")";
+
+ add("keyDown",
+ keySomething + "keypress event.\n" + keyExplain + '\n' + mask,
+ &LLWindowListener::keyDown);
+ add("keyUp",
+ keySomething + "key release event.\n" + keyExplain + '\n' + mask,
+ &LLWindowListener::keyUp);
+ add("mouseDown",
+ mouseSomething + "click event.\n" + mouseExplain + '\n' + mask,
+ &LLWindowListener::mouseDown);
+ add("mouseUp",
+ mouseSomething + "release event.\n" + mouseExplain + '\n' + mask,
+ &LLWindowListener::mouseUp);
+ add("mouseMove",
+ std::string("Given [\"x\"] and [\"y\"], inject the given mouse movement event.\n") +
+ mask,
+ &LLWindowListener::mouseMove);
+ add("mouseScroll",
+ "Given an integer number of [\"clicks\"], inject the given mouse scroll event.\n"
+ "(positive clicks moves downward through typical content)",
+ &LLWindowListener::mouseScroll);
+}
+
+template <typename MAPPED>
+class StringLookup
+{
+private:
+ std::string mDesc;
+ typedef std::map<std::string, MAPPED> Map;
+ Map mMap;
+
+public:
+ StringLookup(const std::string& desc): mDesc(desc) {}
+
+ MAPPED lookup(const typename Map::key_type& key) const
+ {
+ typename Map::const_iterator found = mMap.find(key);
+ if (found == mMap.end())
+ {
+ LL_WARNS("LLWindowListener") << "Unknown " << mDesc << " '" << key << "'" << LL_ENDL;
+ return MAPPED();
+ }
+ return found->second;
+ }
+
+protected:
+ void add(const typename Map::key_type& key, const typename Map::mapped_type& value)
+ {
+ mMap.insert(typename Map::value_type(key, value));
+ }
+};
+
+// for WhichKeysym. KeyProxy is like the typedef KEY, except that KeyProxy()
+// (default-constructed) is guaranteed to have the value KEY_NONE.
+class KeyProxy
+{
+public:
+ KeyProxy(KEY k): mKey(k) {}
+ KeyProxy(): mKey(KEY_NONE) {}
+ operator KEY() const { return mKey; }
+
+private:
+ KEY mKey;
+};
+
+struct WhichKeysym: public StringLookup<KeyProxy>
+{
+ WhichKeysym(): StringLookup<KeyProxy>("keysym")
+ {
+ add("RETURN", KEY_RETURN);
+ add("LEFT", KEY_LEFT);
+ add("RIGHT", KEY_RIGHT);
+ add("UP", KEY_UP);
+ add("DOWN", KEY_DOWN);
+ add("ESCAPE", KEY_ESCAPE);
+ add("BACKSPACE", KEY_BACKSPACE);
+ add("DELETE", KEY_DELETE);
+ add("SHIFT", KEY_SHIFT);
+ add("CONTROL", KEY_CONTROL);
+ add("ALT", KEY_ALT);
+ add("HOME", KEY_HOME);
+ add("END", KEY_END);
+ add("PAGE_UP", KEY_PAGE_UP);
+ add("PAGE_DOWN", KEY_PAGE_DOWN);
+ add("HYPHEN", KEY_HYPHEN);
+ add("EQUALS", KEY_EQUALS);
+ add("INSERT", KEY_INSERT);
+ add("CAPSLOCK", KEY_CAPSLOCK);
+ add("TAB", KEY_TAB);
+ add("ADD", KEY_ADD);
+ add("SUBTRACT", KEY_SUBTRACT);
+ add("MULTIPLY", KEY_MULTIPLY);
+ add("DIVIDE", KEY_DIVIDE);
+ add("F1", KEY_F1);
+ add("F2", KEY_F2);
+ add("F3", KEY_F3);
+ add("F4", KEY_F4);
+ add("F5", KEY_F5);
+ add("F6", KEY_F6);
+ add("F7", KEY_F7);
+ add("F8", KEY_F8);
+ add("F9", KEY_F9);
+ add("F10", KEY_F10);
+ add("F11", KEY_F11);
+ add("F12", KEY_F12);
+
+ add("PAD_UP", KEY_PAD_UP);
+ add("PAD_DOWN", KEY_PAD_DOWN);
+ add("PAD_LEFT", KEY_PAD_LEFT);
+ add("PAD_RIGHT", KEY_PAD_RIGHT);
+ add("PAD_HOME", KEY_PAD_HOME);
+ add("PAD_END", KEY_PAD_END);
+ add("PAD_PGUP", KEY_PAD_PGUP);
+ add("PAD_PGDN", KEY_PAD_PGDN);
+ add("PAD_CENTER", KEY_PAD_CENTER); // the 5 in the middle
+ add("PAD_INS", KEY_PAD_INS);
+ add("PAD_DEL", KEY_PAD_DEL);
+ add("PAD_RETURN", KEY_PAD_RETURN);
+ add("PAD_ADD", KEY_PAD_ADD); // not used
+ add("PAD_SUBTRACT", KEY_PAD_SUBTRACT); // not used
+ add("PAD_MULTIPLY", KEY_PAD_MULTIPLY); // not used
+ add("PAD_DIVIDE", KEY_PAD_DIVIDE); // not used
+
+ add("BUTTON0", KEY_BUTTON0);
+ add("BUTTON1", KEY_BUTTON1);
+ add("BUTTON2", KEY_BUTTON2);
+ add("BUTTON3", KEY_BUTTON3);
+ add("BUTTON4", KEY_BUTTON4);
+ add("BUTTON5", KEY_BUTTON5);
+ add("BUTTON6", KEY_BUTTON6);
+ add("BUTTON7", KEY_BUTTON7);
+ add("BUTTON8", KEY_BUTTON8);
+ add("BUTTON9", KEY_BUTTON9);
+ add("BUTTON10", KEY_BUTTON10);
+ add("BUTTON11", KEY_BUTTON11);
+ add("BUTTON12", KEY_BUTTON12);
+ add("BUTTON13", KEY_BUTTON13);
+ add("BUTTON14", KEY_BUTTON14);
+ add("BUTTON15", KEY_BUTTON15);
+ }
+};
+static WhichKeysym keysyms;
+
+struct WhichMask: public StringLookup<MASK>
+{
+ WhichMask(): StringLookup<MASK>("shift mask")
+ {
+ add("NONE", MASK_NONE);
+ add("CONTROL", MASK_CONTROL); // Mapped to cmd on Macs
+ add("ALT", MASK_ALT);
+ add("SHIFT", MASK_SHIFT);
+ add("MAC_CONTROL", MASK_MAC_CONTROL); // Un-mapped Ctrl key on Macs, not used on Windows
+ }
+};
+static WhichMask masks;
+
+static MASK getMask(const LLSD& event)
+{
+ MASK mask(MASK_NONE);
+ LLSD masknames(event["mask"]);
+ for (LLSD::array_const_iterator ai(masknames.beginArray()), aend(masknames.endArray());
+ ai != aend; ++ai)
+ {
+ mask |= masks.lookup(*ai);
+ }
+ return mask;
+}
+
+static KEY getKEY(const LLSD& event)
+{
+ if (event.has("keysym"))
+ {
+ return keysyms.lookup(event["keysym"]);
+ }
+ else if (event.has("keycode"))
+ {
+ return KEY(event["keycode"].asInteger());
+ }
+ else
+ {
+ return KEY(event["char"].asString()[0]);
+ }
+}
+
+void LLWindowListener::keyDown(LLSD const & evt)
+{
+ mKbGetter()->handleTranslatedKeyDown(getKEY(evt), getMask(evt));
+}
+
+void LLWindowListener::keyUp(LLSD const & evt)
+{
+ mKbGetter()->handleTranslatedKeyUp(getKEY(evt), getMask(evt));
+}
+
+// for WhichButton
+typedef BOOL (LLWindowCallbacks::*MouseFunc)(LLWindow *, LLCoordGL, MASK);
+struct Actions
+{
+ Actions(const MouseFunc& d, const MouseFunc& u): down(d), up(u), valid(true) {}
+ Actions(): valid(false) {}
+ MouseFunc down, up;
+ bool valid;
+};
+
+struct WhichButton: public StringLookup<Actions>
+{
+ WhichButton(): StringLookup<Actions>("mouse button")
+ {
+ add("LEFT", Actions(&LLWindowCallbacks::handleMouseDown,
+ &LLWindowCallbacks::handleMouseUp));
+ add("RIGHT", Actions(&LLWindowCallbacks::handleRightMouseDown,
+ &LLWindowCallbacks::handleRightMouseUp));
+ add("MIDDLE", Actions(&LLWindowCallbacks::handleMiddleMouseDown,
+ &LLWindowCallbacks::handleMiddleMouseUp));
+ }
+};
+static WhichButton buttons;
+
+static LLCoordGL getPos(const LLSD& event)
+{
+ return LLCoordGL(event["x"].asInteger(), event["y"].asInteger());
+}
+
+void LLWindowListener::mouseDown(LLSD const & evt)
+{
+ Actions actions(buttons.lookup(evt["button"]));
+ if (actions.valid)
+ {
+ (mWindow->*(actions.down))(NULL, getPos(evt), getMask(evt));
+ }
+}
+
+void LLWindowListener::mouseUp(LLSD const & evt)
+{
+ Actions actions(buttons.lookup(evt["button"]));
+ if (actions.valid)
+ {
+ (mWindow->*(actions.up))(NULL, getPos(evt), getMask(evt));
+ }
+}
+
+void LLWindowListener::mouseMove(LLSD const & evt)
+{
+ mWindow->handleMouseMove(NULL, getPos(evt), getMask(evt));
+}
+
+void LLWindowListener::mouseScroll(LLSD const & evt)
+{
+ S32 clicks = evt["clicks"].asInteger();
+
+ mWindow->handleScrollWheel(NULL, clicks);
+}
+
diff --git a/indra/llwindow/llwindowlistener.h b/indra/llwindow/llwindowlistener.h
new file mode 100644
index 0000000000..74e577ff93
--- /dev/null
+++ b/indra/llwindow/llwindowlistener.h
@@ -0,0 +1,55 @@
+/**
+ * @file llwindowlistener.h
+ * @brief EventAPI interface for injecting input into LLWindow
+ *
+ * $LicenseInfo:firstyear=2001&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_LLWINDOWLISTENER_H
+#define LL_LLWINDOWLISTENER_H
+
+#include "lleventapi.h"
+#include <boost/function.hpp>
+
+class LLKeyboard;
+class LLWindowCallbacks;
+
+class LLWindowListener : public LLEventAPI
+{
+public:
+ typedef boost::function<LLKeyboard*()> KeyboardGetter;
+ LLWindowListener(LLWindowCallbacks * window, const KeyboardGetter& kbgetter);
+
+ void keyDown(LLSD const & evt);
+ void keyUp(LLSD const & evt);
+ void mouseDown(LLSD const & evt);
+ void mouseUp(LLSD const & evt);
+ void mouseMove(LLSD const & evt);
+ void mouseScroll(LLSD const & evt);
+
+private:
+ LLWindowCallbacks * mWindow;
+ KeyboardGetter mKbGetter;
+};
+
+
+#endif // LL_LLWINDOWLISTENER_H
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index ab089081e6..551d487cc8 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -500,6 +500,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
//-----------------------------------------------------------------------
DEVMODE dev_mode;
+ ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
+ dev_mode.dmSize = sizeof(DEVMODE);
DWORD current_refresh;
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
{
@@ -878,6 +880,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
{
GLuint pixel_format;
DEVMODE dev_mode;
+ ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
+ dev_mode.dmSize = sizeof(DEVMODE);
DWORD current_refresh;
DWORD dw_ex_style;
DWORD dw_style;
@@ -2711,6 +2715,8 @@ LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_re
{
mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
DEVMODE dev_mode;
+ ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
+ dev_mode.dmSize = sizeof(DEVMODE);
mNumSupportedResolutions = 0;
for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++)
@@ -2786,7 +2792,8 @@ F32 LLWindowWin32::getPixelAspectRatio()
BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
{
DEVMODE dev_mode;
- dev_mode.dmSize = sizeof(dev_mode);
+ ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
+ dev_mode.dmSize = sizeof(DEVMODE);
BOOL success = FALSE;
// Don't change anything if we don't have to
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index e24ee6629e..9ba8edbb59 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -492,6 +492,15 @@ private:
////////////////////////////////////////////////////////////////////////////////
// virtual
+ void onNavigateErrorPage(const EventType& event)
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
+ message.setValueS32("status_code", event.getIntValue());
+ sendMessage(message);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // virtual
void onLocationChange(const EventType& event)
{
if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
@@ -519,6 +528,11 @@ private:
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
message.setValue("uri", event.getEventUri());
+#if LLQTWEBKIT_API_VERSION >= 7
+ message.setValue("nav_type", event.getNavigationType());
+#else
+ message.setValue("nav_type", "clicked");
+#endif
sendMessage(message);
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 3740b1a742..1d155add51 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -427,6 +427,7 @@ set(viewer_SOURCE_FILES
llsidepaneliteminfo.cpp
llsidepaneltaskinfo.cpp
llsidetray.cpp
+ llsidetraylistener.cpp
llsidetraypanelcontainer.cpp
llsky.cpp
llslurl.cpp
@@ -970,6 +971,7 @@ set(viewer_HEADER_FILES
llsidepaneliteminfo.h
llsidepaneltaskinfo.h
llsidetray.h
+ llsidetraylistener.h
llsidetraypanelcontainer.h
llsky.h
llslurl.h
diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem
index 7cebbf48b2..63bb036c92 100644
--- a/indra/newview/app_settings/CA.pem
+++ b/indra/newview/app_settings/CA.pem
@@ -128,2094 +128,999 @@ TBA+9zBb6xD1KM2DdY7r4GiyYItN0BKLfuWbh9LXGbl1C+f4P11g+m2MPiavIeCe
1iazG5pcS3KoTLACsYlEX24TINtg4kcuS81XdllcnsV3Kdts0nIqPj6uhTTZD0k=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF
-BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz
-aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC
-QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry
-dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw
-CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x
-FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS
-b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC
-AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK
-pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV
-6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc
-OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV
-jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9
-cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C
-AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k
-qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT
-ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg
-TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm
-/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx
-fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ
-TzFxiNmIf1Q=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4
-dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h
-bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL
-MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B
-ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1
-c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8
-k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50
-ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504
-B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez
-eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5
-aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB
-3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD
-AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6
-xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv
-cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ
-KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
-j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R
-xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT
-K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1
-n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx
-REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O
-hgQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw
-HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze
-xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI
-gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O
-M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc
-sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5
-mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG
-9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU
-tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
-MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw
-CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
-ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx
-IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0
-MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
-iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9
-tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL
-/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV
-g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6
-tkD9xOQ14R0WHNC8K47Wcdk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe
-Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF
-MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
-IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+
-A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c
-+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2
-P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX
-C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R
-s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9
-BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf
-d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB
-jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG
-A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
-cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB
-IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu
-G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
-+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj
-PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY
-GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6
-NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx
-My3ZdvJOOjMMK7MtkAY=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT
-RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU
-UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v
-dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT
-AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg
-VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS
-b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek
-n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk
-IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z
-sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t
-UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R
-+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES
-a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5
-lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
-AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw
-ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
-ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh
-bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh
-lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
-GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9
-5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF
-Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA
-wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw
-dOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l
-cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X
-DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx
-HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp
-Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa
-xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl
-GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n
-BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx
-VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE
-mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu
-JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5
-9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA
-A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
-Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM
-IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI
-dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
-Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j
-8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l
-cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X
-DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx
-HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp
-Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw
-DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN
-t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/
-DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x
-uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE
-18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr
-kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD
-bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX
-uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu
-Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9
-W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
-o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48
-ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn
-AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
-aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee
-MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL
-M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf
-tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR
-Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R
-+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr
-+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM
-nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt
-d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI
-WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ
-ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y
-3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz
-2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
RY8mkaKO/qk=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB
-bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw
-MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB
-T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg
-SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI
-zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt
-fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs
-trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr
-5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc
-LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw
-DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+
-XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/
-BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM
-eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7
-CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf
-WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT
-LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz
-vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw
-X7A5KGgOc90lmt4S
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB
-bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw
-MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB
-T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg
-SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
-ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs
-RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs
-i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg
-/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ
-2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0
-ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X
-+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml
-J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh
-EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo
-Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ
-Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex
-MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB
-Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA
-FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
-9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0
-cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF
-ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY
-vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/
-drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la
-5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks
-mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5
-O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD
-062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41
-xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H
-hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL
-Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG
-EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0
-MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx
-MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV
-BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ
-QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h
-Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR
-QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP
-wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1
-pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT
-Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC
-AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud
-EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA
-A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT
-I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
-jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/
-oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67
-G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
-RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK
-EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG
-A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0
-aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE
-ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx
-BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh
-dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW
-HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R
-9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3
-fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f
-HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm
-iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg
-B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB
-/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR
-MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl
-IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu
-dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k
-YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj
-YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0
-eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT
-VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj
-dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3
-dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww
-HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9
-w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B
-AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z
-dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9
-beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ
-XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d
-UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py
-05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG
-EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg
-Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy
-MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV
-BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow
-GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4
-SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3
-o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V
-cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k
-bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8
-tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC
-AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB
-TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp
-YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz
-IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0
-ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u
-IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl
-VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t
-L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU
-ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD
-VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub
-2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir
-ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax
-6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl
-pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE
-/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA
-AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH
-0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG
-EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK
-EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG
-A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0
-aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE
-ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx
-BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh
-dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1
-Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw
-ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV
-m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb
-hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu
-6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX
-LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g
-BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH
-AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj
-YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug
-b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u
-ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0
-YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj
-aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0
-cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl
-eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t
-L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD
-AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl
-ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS
-VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx
-MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa
-j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV
-HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq
-hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04
-ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB
-evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220
-Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2
-KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi
-aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep
-9w==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF
-ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS
-b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w
-bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi
-MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290
-IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt
-ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw
-CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK
-Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU
-vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL
-O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe
-rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1
-S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV
-HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD
-kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v
-cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB
-OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj
-cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo
-ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv
-bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l
-bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu
-IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93
-d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s
-MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN
-GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF
-BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0
-3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt
-NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1
-UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM
-m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y
-mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYT
-AlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNl
-cnR1bSBDQTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJ
-BgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNV
-BAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-AM6xwS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYV
-M42sLQnFdvkrOYCJ5JdLkKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/Ox
-LjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE
-7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/KUz/iDsaW
-VhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu
-/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYD
-VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESS
-bLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQaTOs9qmdvLdTN
-/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvgGrZg
-FCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqT
-E5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
-O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYV
-IZQs6GAqm4VKQPNriiTsBhYscw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJH
-QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm
-b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFB
-IENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIz
-MTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
-Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENB
-IExpbWl0ZWQxITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5AnfRu4ep2hxxNRUSO
-vkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhGC1Pqy0wk
-wLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfH
-dr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf04
-9vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULi
-mAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cmez6KJcfA3Z3m
-NWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEKIz6W
-8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
-Af8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
-QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwu
-Y29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG
-9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
-7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHC
-v8S5dIa2LX1rzNLzRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdV
-CYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAV
-GI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C12yxow+ev+to
-51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJH
-QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm
-b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2Vj
-dXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4
-MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIg
-TWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2Rv
-IENBIExpbWl0ZWQxJDAiBgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2
-aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBxM4KK0HDr
-c4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP9nQ95IDC
-+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8
-j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWC
-iIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtG
-Cd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz6YiO/O1R65Nx
-Tq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4EFgQU
-PNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
-/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
-Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNo
-dHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNl
-cy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
-4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiF
-Gv45jN5bBAS0VPmjZ55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXG
-De+X3EyrEeFryzHRbPtIgKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsF
-Vy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfU
-a7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6s
-Cx1HRR3B7Hzs/Sk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJH
-QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm
-b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1
-c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0y
-ODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVy
-IE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9k
-byBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNl
-cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhT
-WvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh73TkVvFVI
-xO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9
-C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/
-oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW1O24zG71++IsWL1/
-T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7kUlcsutT6vif
-R4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1UdDgQW
-BBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
-ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2
-hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2Vy
-dmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
-uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdT
-mw7pSqBYaWcOrp32pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+C
-l5EfKNsYEYwq5GWDVxISjBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/g
-hhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVF
-wL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOj
-GM9O9y5Xt5hwXsjEeLBi
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG
-EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw
-DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw
-MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy
-ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB
-AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR
-EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth
-zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0
-dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E
-YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg
-U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx
-MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3
-pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV
-HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3
-DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
-QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA
-sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6
-w4pl
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp
-MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM
-YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv
-LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx
-ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx
-ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE
-CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp
-Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx
-FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp
-Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U
-q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF
-koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh
-TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd
-lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn
-7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG
-9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+
-LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV
-WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX
-8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8
-6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT
-F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG
-EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw
-DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3
-MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy
-ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB
-AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB
-w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e
-ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd
-55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E
-YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg
-U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw
-OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s
-NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV
-HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3
-DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
-xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb
-dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih
-w6ID
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp
-MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM
-YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv
-LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx
-ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy
-MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE
-CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp
-Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx
-FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp
-Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6
-ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5
-/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9
-MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih
-YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv
-bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG
-9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog
-WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6
-HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV
-6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8
-PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30
-sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB
-X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
-HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
-c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy
-MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0
-Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y
-cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg
-RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp
-ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU
-rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB
-3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y
-NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E
-gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw
-PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy
-ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0
-Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
-IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD
-AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW
-BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2
-fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA
-O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L
-a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l
-TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf
-Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
-KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz
-dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF
-bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg
-aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg
-MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l
-dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G
-CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw
-tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK
-wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI
-XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD
-AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu
-dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy
-MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0
-IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV
-BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw
-NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc
-/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV
-HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq
-hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv
-yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp
-bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/
-bIkz8OwVDw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE
-ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf
-MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT
-HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1
-c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy
-MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0
-Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y
-cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg
-RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4
-QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC
-DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj
-/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP
-KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd
-enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB
-0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ
-FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B
-AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh
-fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU
-KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho
-wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2
-+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888
-6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE
-BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50
-cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs
-aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp
-bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0
-aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa
-MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV
-BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw
-LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50
-cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL
-ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv
-x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV
-iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173
-iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw
-ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
-cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff
-SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE
-CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50
-cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD
-VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D
-bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx
-MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW
-/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG
-A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
-hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ
-OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU
-ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE
-PHayXOw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE
-BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50
-cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
-MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE
-AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw
-CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3
-dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh
-Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow
-OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
-b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0
-VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN
-iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk
-mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT
-MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY
-pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
-BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs
-aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM
-aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo
-dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi
-gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC
-AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE
-FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9
-B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn
-CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx
-xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6
-rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG
-EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1
-cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4
-MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx
-LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0
-eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R
-FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO
-/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv
-K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp
-MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt
-MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
-MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL
-BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw
-HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w
-GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB
-AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u
-FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1
-aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN
-MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh
-eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu
-ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe
-k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5
-/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW
-HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG
-SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4
-MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq
-R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm
-JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1
-tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr
-tWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG
-EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm
-YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5
-MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg
-U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et
-MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF
-7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD
-pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM
-HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp
-MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT
-ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y
-MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL
-BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw
-HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w
-GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB
-AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
-0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt
-y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV
-UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1
-aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0
-MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT
-E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl
-IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
-gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy
-td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR
-OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC
-AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w
-HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o
-oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf
-2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa
-z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1
-pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT
-AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz
-dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
-AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH
-CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC
-GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7
-csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj
-Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe
-JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB
-o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9
-qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq
-hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe
-R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV
-Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
-PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot
-2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX
-xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
-Mw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL
-MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV
-BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05
-ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw
-FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw
-GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR
-4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc
-71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4
-bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK
-OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW
-ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP
-AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ
-UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC
-AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd
-PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
-gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT
-2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD
-NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg
-Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw
-FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy
-dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg
-R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1
-MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD
-VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT
-GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4
-ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn
-ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F
-LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3
-46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq
-81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d
-XIVtx6quTx8itc2VrbqnzPmrC3p/
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw
-FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy
-dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw
-CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD
-ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K
-DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw
-KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID
-AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD
-+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv
-U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e
-6bR64eVaH4QwnNOfpSXY
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjEzMDEGA1UECxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5MTMwMQYDVQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlw
-cy5lczAeFw0wMTEyMjkwMDUzNThaFw0yNTEyMjcwMDUzNThaMIIBHDELMAkG
-A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs
-b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl
-cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw
-OTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFpbmVkIENBcyBD
-ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1h
-aWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJspQg
-vJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB
-hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQT
-y2nBBt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8w
-HQYDVR0OBBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCC
-AUGAFKGtMbH5PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQG
-EwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmEx
-LjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMu
-bC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0
-NTIxMzAxBgNVBAsTKklQUyBDQSBDaGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9u
-IEF1dGhvcml0eTEzMDEGA1UEAxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5p
-cHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRk
-MGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggr
-BgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK
-KwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBz
-QG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglg
-hkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg
-aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3
-Lmlwcy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5p
-cHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYt
-aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/
-MDkGCWCGSAGG+EIBBwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl
-bmV3YWxDQUMuaHRtbD8wNwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBz
-LmVzL2lwczIwMDIvcG9saWN5Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYo
-aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCg
-LoYsaHR0cDovL3d3d2JhY2suaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNBQy5j
-cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p
-cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1WWKJBGyi3leGmGpVfp3hA
-K+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfNHnNDJGD1HWHc3Jag
-vPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvNb2ar7QMiRDjM
-Wb2f2/YHogF/JsRj9SVCXmK9
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx
-MTIyOTAwNTkzOFoXDTI1MTIyNzAwNTkzOFowggESMQswCQYDVQQGEwJFUzES
-MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV
-BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp
-BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs
-BgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
-LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG
-9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywSzHb5
-BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS
-YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJ
-ZHMQKD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzc
-uh9morKbadB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKb
-adB4CKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl
-bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu
-ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp
-bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg
-Q0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg
-Q0EgQ0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN
-AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E
-BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH
-AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB
-FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw
-GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt
-YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRpZmlj
-YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC
-BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt
-FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3Js
-MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl
-dm9jYXRpb25DTEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93
-d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgB
-hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT
-RTEuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p
-cHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj
-ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UxLmNybDAvBggrBgEFBQcB
-AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI
-hvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuKYn4VLenZMdMu9Ccj/1ur
-xUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpjV4F1Wo7ojPsCwJTG
-Kbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+hjM+5i9Ibq9U
-kE6tsSU=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx
-MTIyOTAxMDE0NFoXDTI1MTIyNzAxMDE0NFowggESMQswCQYDVQQGEwJFUzES
-MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV
-BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp
-BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs
-BgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
-LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG
-9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZH49N
-zjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY
-8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBx
-RiVrSXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLn
-ev42USGjmFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGj
-mFsMNKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl
-bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu
-ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp
-bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg
-Q0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg
-Q0EgQ0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN
-AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E
-BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH
-AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB
-FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw
-GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt
-YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRpZmlj
-YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC
-BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt
-FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3Js
-MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl
-dm9jYXRpb25DTEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93
-d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgB
-hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT
-RTMuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p
-cHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj
-ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UzLmNybDAvBggrBgEFBQcB
-AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI
-hvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dDqsfwfewPxqmurpYPdikc
-4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9D6eSb9ijBmgpjnn1
-/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGyr33I6unUVtkO
-E7LFRVA=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN
-MDExMjI5MDEwNTMyWhcNMjUxMjI3MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVT
-MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG
-A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr
-MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv
-MC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8m2md
-d81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd
-ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1
-e+J8eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/
-2LUDnf473P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf47
-3P7yiuYV3TChggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC
-YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu
-dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz
-QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT
-IENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT
-JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ
-KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM
-BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI
-KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB
-BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE
-BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB
-D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBDQSBD
-ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG
-SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB
-hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB
-U0VBMS5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw
-czIwMDIvcmV2b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAW
-Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRt
-bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv
-cG9saWN5Q0xBU0VBMS5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93
-d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTEuY3JsMDagNKAyhjBo
-dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j
-cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p
-cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyAAIQVCtWYUQxkxZwCWINm
-yq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeFaQoO42Hu6r4okzPV
-7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aLH2betgPAK7N4
-1lUH5Y85UN4HI3LmvSAUS7SG
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN
-MDExMjI5MDEwNzUwWhcNMjUxMjI3MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVT
-MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG
-A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr
-MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv
-MC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ
-KoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvNG7uG
-BiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU
-VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4
-Ninn6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2
-YZM50yz82l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz8
-2l09BXW3mQKhggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC
-YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu
-dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz
-QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT
-IENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT
-JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ
-KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM
-BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI
-KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB
-BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE
-BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB
-D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBDQSBD
-ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG
-SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB
-hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB
-U0VBMy5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw
-czIwMDIvcmV2b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAW
-Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRt
-bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv
-cG9saWN5Q0xBU0VBMy5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93
-d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTMuY3JsMDagNKAyhjBo
-dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j
-cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p
-cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca2on0eisxeewBwMwB9dbB
-/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI3y2s6Q73nMify5NF
-8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYSAfWRMS1Jjbs/
-RU4s4OjNtckUFQzjB4ObJnXv
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIw
-EAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE
-ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVz
-MRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBz
-QG1haWwuaXBzLmVzMB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1ow
-gaMxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcT
-CUJBUkNFTE9OQTEZMBcGA1UEChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UE
-CxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEe
-MBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEB
-AQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGbWOlI6H0fg3
-PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU
-3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzh
-PvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lYJN7GO9HgQmm4
-7mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsUdx+2/iU9
-4aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14cJ58
-GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYT
-AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu
-MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s
-LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1
-MjE0MDIGA1UECxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9u
-IEF1dGhvcml0eTE0MDIGA1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu
-aXBzLmVzMB4XDTAxMTIyOTAxMTAxOFoXDTI1MTIyNzAxMTAxOFowggEeMQsw
-CQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJj
-ZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZp
-Y2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEIt
-NjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3RhbXBpbmcgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBUaW1lc3RhbXBp
-bmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lw
-c0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLju
-VqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4
-Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6
-KaFYq6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAw
-ggR8MB0GA1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSC
-AUcwggFDgBSL0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkG
-A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs
-b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl
-cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw
-OTI5NDUyMTQwMgYDVQQLEytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5MTQwMgYDVQQDEytJUFMgQ0EgVGltZXN0YW1waW5n
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNA
-bWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsG
-A1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUF
-BwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGC
-NwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw
-EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5l
-czBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl
-IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwW
-Gmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFo
-dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcu
-Y3JsMEUGCWCGSAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAy
-L3Jldm9jYXRpb25UaW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUW
-M2h0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGlu
-Zy5odG1sPzBABglghkgBhvhCAQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBz
-MjAwMi9wb2xpY3lUaW1lc3RhbXBpbmcuaHRtbDB/BgNVHR8EeDB2MDegNaAz
-hjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBp
-bmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9p
-cHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYB
-BQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEA
-ZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk36MNbsMRnLWha
-sl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I3pGW7hdb
-rqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQG
-EwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9v
-dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNa
-Fw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9W
-YWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1
-lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMukJ0KX0J+D
-isPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj18
-2d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Sp
-x2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZ
-yH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospUxbF6lR1xHkop
-igPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4wPQYI
-KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFk
-aXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
-ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlh
-bmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBw
-YXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
-ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRp
-ZmljYXRpb24gcHJhY3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmlj
-YXRlIFBvbGljeS4wIgYIKwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMu
-Ym0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYw
-gaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJN
-MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCLMA4GA1UdDwEB/wQEAwIB
-BjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lofFIk3Wdv
-OXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10
-buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe
-/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6
-isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
-xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQ
-NiOKSnQ2+Q==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f
-NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM
-MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34
-t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b
-e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu
-PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
-PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF
-ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg
-U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx
-NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT
-QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
-gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY
-rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt
-bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB
-o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME
-GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N
-AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy
-HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9
-am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B
-qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF
-ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg
-U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5
-MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT
-QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37
-RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E
-0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J
-6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq
-s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD
-uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw
-YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW
-gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6
-/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V
-EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g
-EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
-f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq
-aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk
-llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
-pKnXwiJPZ9d37CAFYd4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJK
-UDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0
-eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMw
-OTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1
-c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RD
-QTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8
-V6UMbXaKL0u/ZPtM7orw8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpx
-xpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uMDPpVmDvY6CKhS3E4eayXkmmz
-iX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX5HA49LY6
-tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819
-uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/L
-TX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZ
-aNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g0dNq
-/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94
-nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
-Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNn
-PaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfci
-oU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
-FL39vmwLAw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG
-STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENB
-MB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMC
-RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBD
-QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue
-+H887dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mX
-y47vPxVnqIJyY1MPQYx9EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNY
-wBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JF
-hfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF6452F/NM8Ec
-yonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW
-1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB
-/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB
-BQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuXZfsSZ9gqXLar
-5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxVyhbM
-p6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2
-nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
-kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2y
-Ix4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG
-STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENB
-MB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMC
-RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBD
-QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE
-+hY3/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gX
-GM2RX/uJ4+q/Tl18GybTdXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQ
-TiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMGf+dJQMjFAbJUWmYdPfz56TwK
-noG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8PtOFCx4j1
-P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURr
-BGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB
-/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB
-BQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zilzqsWuasvfDXL
-rNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEIcbCd
-jdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr4
-50kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
-Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkeja
-nZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG
-EwJOTDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQD
-Ex1TdGFhdCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIz
-NDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVT
-dGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRl
-cmxhbmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAmNK1URF6gaYUmHFtvsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rF
-DBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02PjLwYdjeFnejKScfST5gTCaI+
-Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGcaC1Hoi6Ce
-UJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7l
-r7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4Zl
-kuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGO
-MAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDwwOgYIKwYBBQUH
-AgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9vdC1w
-b2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg
-0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
-/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVF
-IGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0
-C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
-nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBp
-IzlWYGeQiy52OfsRiJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYV
-wSR8MnwDHTuhWEUykw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT
-AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD
-VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3
-b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB
-MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe
-Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE
-RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE
-ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y
-a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp
-MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk
-qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO
-gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7
-zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w
-DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
-CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W
-LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR
-T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac
-ASZ4smZHcFFk
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT
-AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD
-VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3
-b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB
-MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe
-Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE
-RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE
-ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y
-a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp
-MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w
-DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ
-GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn
-v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA
-o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w
-DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
-CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4
-iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC
-GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS
-CdS7kjXvD9s0
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQG
-EwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50
-ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTda
-MEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNV
-BAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4Nr
-XceO+YQwzho7+vvOi20jxsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaq
-HF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5
-Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc5IogCSEW
-Vmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8n
-mHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwID
-AQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBY
-oFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0w
-GwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTAr
-BgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjAL
-BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
-HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8w
-HQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
-A4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m
-gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKs
-LtB9KOy282A4aW8+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7T
-mHnaCB4Mb7j4Fifvwm899qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE
-64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQ
-V0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQG
-EwJESzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0w
-MzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQww
-CgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSj
-hFuHnEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8
-z3sM8W9Hpg1DTeLpHTk0zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJH
-hNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvViGjaXbXqzRowwYCDdlCqT9HU
-3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBdedObaE+3p
-Hx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTw
-tyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-Af8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYB
-BQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBvc2l0b3J5MIGd
-BggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBmcmEg
-ZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x
-LiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
-T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEG
-A1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERD
-MRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm
-aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0Q
-BCQwIoAPMjAwMzAyMTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0j
-BBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4S
-GSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDAN
-BgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBu
-o7E4A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjND
-fZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8Aqt
-FxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoBmbgGglGBTvH1tJFUuSN6
-AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1AoLbrIyi
-gfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2Lq
-L19iUw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl
-cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp
-Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow
-gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV
-BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm
-BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV
-BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ
-cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB
-jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK
-P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ
-fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j
-kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB
-gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
-c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95
-B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl
-cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m
-cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz
-NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx
-EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp
-bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
-JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG
-SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq
-hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N
-j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef
-QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY
-x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
-hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
-MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC
-neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr
-5PjRzneigQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl
-cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy
-ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5
-NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw
-EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n
-MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw
-IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3
-DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7
-7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j
-Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq
-W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
-DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
-b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx
-eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1
-KzGJ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
-dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl
-IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
-cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1
-OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ
-BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg
-Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
-ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3
-DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI
-NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL
-lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN
-9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
-AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
-hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ
-a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU
-Qg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
-MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
-dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl
-IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
-ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG
-A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw
-ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
-CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ
-VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz
-QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I
-/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC
-6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX
-TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G
-A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD
-TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
-QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni
-TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC
-WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls
-bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj
-YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw
-MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT
-BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
-BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x
-HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN
-AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8
-WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR
-5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7
-X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
-AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK
-0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8
-zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ
-SdM=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUF
-ADCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVU
-TiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2
-MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNh
-bHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx
-ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMS
-VVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+O
-GQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrr
-U0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrL
-Z9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8
-oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+
-Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4Gr
-MIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
-MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8v
-Y3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUE
-IzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
-DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHc
-rpY6CiM+iVnJowftGzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuM
-FrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1
-+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdO
-jtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jF
-VkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUF
-ADCBrjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVU
-Ti1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAe
-Fw05OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJV
-UzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
-VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93
-d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJzdC1DbGll
-bnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxq
-mNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqk
-kqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6lL8/K2m2qL+us
-obNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHGTPNp
-saguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZU
-Ot4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
-6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0G
-A1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJ
-hkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll
-bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEF
-BQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rk
-MPxTbyUkxsrt4jFcKw7u7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK
-2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/
-bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJR
-warVNZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf
-6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQ
-jvLzxq4oW6fw8zYX/MMF08oDSlQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUF
-ADCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVU
-Ti1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5
-MTgxOTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQH
-Ew5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3
-b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNV
-BAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZ
-FvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6N
-q9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEH
-OG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNdoI6yqqr2jmmI
-BsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjfPe58
-BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhb
-AgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWG
-M2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3
-YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
-BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0o
-XnWO6y1n7k57K9cM//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjA
-bPLPSbtNk28GpgoiskliCE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59
-Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4f
-Fm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchq
-J/kniCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0q
-UZ6B+dQ7XnASfxAynB67nfhmqA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF
-ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU
-Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0
-ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT
-AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT
-RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz
-dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh
-dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV
-hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb
-GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ
-NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4
-xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv
-/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i
-gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
-AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf
-8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0
-LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G
-CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh
-i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq
-f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf
-hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP
-NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+
-FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis
-H8SE
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUF
-ADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
-IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw
-HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVU
-Ti1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4
-NDAzNlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMO
-U2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29y
-azEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQD
-ExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r55
-96Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc
-/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2
-yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+pKvEHDHd17bR
-5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7RwvC
-bNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEA
-AaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0
-cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNy
-bDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw
-DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXF
-wfNfLEzIR1pp6ujwNTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T
-7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85
-dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U
-+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCA
-GKCGhU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2o
-Ps0AH8g=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw
-8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m
-+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN
-dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V
-YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so
-gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
-nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx
+HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh
+IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1
+MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg
+SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M
+IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U
+0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI
+TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf
+RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF
+zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh
+BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA
+AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY
+PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/
+BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn
+9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT
+Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF
+Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX
+n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW
+H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx
+HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh
+IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz
+NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg
+SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M
+IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ
+7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb
+m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY
+xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ
+YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq
+JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx
+I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz
+kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh
+EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S
+Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM
+gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu
+rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO
+1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu
+h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP
+yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q
+7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT
+RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/
+ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB
+M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ
+my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO
+AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT
+9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H
+hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5
+fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq
+YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy
+MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk
+MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl
+ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i
+805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6
+l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B
+FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp
+kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7
+eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa
+MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A
+AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig
+dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu
+dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk
+IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g
+UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l
+bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl
+LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k
+ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By
+b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc
+cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud
+DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA
+WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6
+7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY
+gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb
+4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9
+CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq
+YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy
+MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk
+MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl
+ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO
+K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD
+d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj
+DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe
+yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt
+VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB
+MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI
+KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp
+ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug
+b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg
+Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0
+cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF
+BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz
+L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug
+eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv
+b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w
+bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw
+ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA
+FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw
+qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE
+kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ
+5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB
+evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz
+ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k
+XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh
+xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi
+MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB
+czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp
+b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli
+ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm
+YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn
+HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I
+1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk
+tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU
+GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er
+cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY
+MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+
+AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j
+b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB
+OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh
+dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu
+IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl
+LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS
+ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo
+ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w
+cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME
+GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt
+z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g
+6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK
+mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd
+LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb
+J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3
+SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg
+bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ
+j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV
+Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw
+MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5
+fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i
++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
+QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+
+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/
+k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso
+LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o
+TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3
+MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C
+TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5
+WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
+xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL
+B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy
+MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny
+Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0
+iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn
+5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd
+BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0
+MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy
+ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l
+dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy
+MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY
+MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF
+fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w
+AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS
+hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/
+GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd
+zmVml64mXg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML
+RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu
+Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg
+RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl
+IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa
+Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE
+CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO
+8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB
+bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2
+dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4
+QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT
+C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw
+IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy
+ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw
+KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD
+VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud
+DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2
+fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia
+d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF
+JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U
+yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u
+ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh
+Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU
+MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D
+bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq
+RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G
+CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo
+6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux
+5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm
+AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC
+ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
+cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m
+by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp
+IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg
+Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg
+KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV
+HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E
+BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE
+FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7
+pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz
+wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a
+EkP/TOYGJqibGapEPHayXOw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD
-ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
-Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp
-b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv
-bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy
-NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
-IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x
-NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
-QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x
-IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3
-DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc
-65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ
-b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn
-wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4
-OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ
-oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
-W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE
-CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV
-BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
-c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3
-noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B
-9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg
-1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM
-P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P
-/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj
-t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq
-0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9
-Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c
-PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr
-bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
-uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i
-P/68DzFc6PLZ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR
-ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j
-Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh
-JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P
-oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
-6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh
-v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ
-BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N
-y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf
-xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM
-DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5
-SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV
-OBRgmaNL3gaWcSzy27YfpO8/7g==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL
-Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM
-JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE
-erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC
-JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob
-K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg
-MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3
-Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV
-BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g
-LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g
-VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla
-MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6
-BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu
-Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp
-Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
-p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf
-rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z
-Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN
-BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/
-7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
-rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x
-RnInjBJ7xUS0rg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE
-CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg
-VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG
-A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx
-NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg
-SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE
-CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1
-c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp
-bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8
-1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT
-2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT
-AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ
-HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
-qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC
-YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh
-ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf
-0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE
-p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B
-MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab
-5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX
-p/naOlXJWBD5qu9ats9LS98q
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL
-Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q
-RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In
-zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a
-/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM
-EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw
-TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk
-uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM
-XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX
-wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV
-j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U
-bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
-F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo
-1KpYoJ2daZH9
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2
-R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo
-vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg
-TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V
-k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ
-OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my
-/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
-j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA
-Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S
-GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb
-o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh
-/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx
-CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE
-CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt
-IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU
-cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG
-A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j
-LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln
-biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6
-8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK
-QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX
-xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G
-CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI
-L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
-cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt
-ImRPT8qAkbYp
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV
-BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5
-IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD
-BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3
-MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s
-IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV
-BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg
-dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy
-aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl
-S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC
-KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc
-VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL
-MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
-ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD
-Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr
-IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
-mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK
-vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP
-QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP
-mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr
-9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL
-MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu
-MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE
-BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
-VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb
-MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O
-LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs
-iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC
-sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw
-4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr
-l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1
-g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF
-ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww
-OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g
-QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1
-OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh
-dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD
-EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq
-hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2
-fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/
-RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB
-CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG
-A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz
-Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0
-cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG
-CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp
-c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2
-DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn
-Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n
-tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF
-ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz
-YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT
-E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0
-MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE
-CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa
-BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
-A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh
-28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362
-rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81
-q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF
-Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0
-lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t
-AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
-A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC
-AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
-zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht
-cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI
-xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
-YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/
-hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC
-VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h
-bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN
-MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN
-MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl
-cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ
-DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ
-XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl
-Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm
-7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa
-xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e
-QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO
-qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
-SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp
-NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ
-kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL
-axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt
-Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8
-ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
+YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
+5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
+gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
+rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
+ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
+Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq
+SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD
+VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
+HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMjkwMDUzNTha
+Fw0yNTEyMjcwMDUzNThaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl
+bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg
+cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu
+ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD
+QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp
+bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP
+aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJ
+spQgvJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB
+hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQTy2nB
+Bt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8wHQYDVR0O
+BBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCCAUGAFKGtMbH5
+PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE
+CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ
+bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt
+YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD
+aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT
+IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI
+hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E
+BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG
+CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB
+BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw
+EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBC
+BglghkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg
+aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlw
+cy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5pcHMuZXMv
+aXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYtaHR0cDovL3d3
+dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/MDkGCWCGSAGG+EIB
+BwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3JlbmV3YWxDQUMuaHRtbD8w
+NwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5
+Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYoaHR0cDovL3d3dy5pcHMuZXMvaXBz
+MjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCgLoYsaHR0cDovL3d3d2JhY2suaXBzLmVz
+L2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF
+BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1W
+WKJBGyi3leGmGpVfp3hAK+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfN
+HnNDJGD1HWHc3JagvPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvN
+b2ar7QMiRDjMWb2f2/YHogF/JsRj9SVCXmK9
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl
+SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl
+SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3
+DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAwNTkzOFoXDTI1MTIyNzAw
+NTkzOFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD
+VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n
+IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g
+IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywS
+zHb5BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS
+YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJZHMQ
+KD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzcuh9morKb
+adB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKbadB4CKGCARqk
+ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE
+BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT
+ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC
+LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD
+VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr
+BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB
+FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC
+AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB
+D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRp
+ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC
+BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito
+dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMD8GCWCG
+SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D
+TEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw
+czIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov
+L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDBzBgNVHR8EbDBq
+MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEu
+Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy
+Q0xBU0UxLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v
+Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuK
+Yn4VLenZMdMu9Ccj/1urxUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpj
+V4F1Wo7ojPsCwJTGKbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+
+hjM+5i9Ibq9UkE6tsSU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl
+SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl
+SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3
+DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMDE0NFoXDTI1MTIyNzAx
+MDE0NFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD
+VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n
+IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g
+IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZ
+H49NzjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY
+8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBxRiVr
+SXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLnev42USGj
+mFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGjmFsMNKGCARqk
+ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE
+BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT
+ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC
+LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD
+VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr
+BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB
+FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC
+AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB
+D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRp
+ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC
+BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito
+dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMD8GCWCG
+SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D
+TEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw
+czIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov
+L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDBzBgNVHR8EbDBq
+MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMu
+Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy
+Q0xBU0UzLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v
+Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dD
+qsfwfewPxqmurpYPdikc4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9
+D6eSb9ijBmgpjnn1/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGy
+r33I6unUVtkOE7LFRVA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm
+SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT
+JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI
+hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNTMyWhcNMjUxMjI3
+MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ
+BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp
+bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G
+LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8
+m2mdd81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd
+ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1e+J8
+eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/2LUDnf47
+3P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf473P7yiuYV3TCh
+ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ
+BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp
+bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G
+LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC
+AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF
+BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB
+BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg
+hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud
+EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBD
+QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG
+SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC
+AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j
+cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2
+b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu
+aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRtbD8wOwYJYIZIAYb4QgEI
+BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMS5odG1s
+MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz
+MjAwMkNMQVNFQTEuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz
+MjAwMi9pcHMyMDAyQ0xBU0VBMS5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF
+BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyA
+AIQVCtWYUQxkxZwCWINmyq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeF
+aQoO42Hu6r4okzPV7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aL
+H2betgPAK7N41lUH5Y85UN4HI3LmvSAUS7SG
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm
+SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT
+JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI
+hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNzUwWhcNMjUxMjI3
+MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ
+BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp
+bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G
+LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvN
+G7uGBiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU
+VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4Ninn
+6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2YZM50yz8
+2l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz82l09BXW3mQKh
+ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ
+BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp
+bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G
+LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC
+AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF
+BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB
+BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg
+hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud
+EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBD
+QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG
+SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC
+AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j
+cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2
+b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu
+aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRtbD8wOwYJYIZIAYb4QgEI
+BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMy5odG1s
+MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz
+MjAwMkNMQVNFQTMuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz
+MjAwMi9pcHMyMDAyQ0xBU0VBMy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF
+BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca
+2on0eisxeewBwMwB9dbB/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI
+3y2s6Q73nMify5NF8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYS
+AfWRMS1Jjbs/RU4s4OjNtckUFQzjB4ObJnXv
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE
+ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE
+ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr
+SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG
+A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMTAx
+OFoXDTI1MTIyNzAxMTAxOFowggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy
+Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l
+dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw
+cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh
+bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU
+aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B
+CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+vLjuVqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4
+Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6KaFY
+q6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAwggR8MB0G
+A1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSCAUcwggFDgBSL
+0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ
+BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ
+UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp
+cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg
+Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD
+EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w
+HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM
+BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB
+BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB
+FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD
+VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw
+cy5lczBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl
+IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwWGmh0
+dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFodHRwOi8v
+d3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEUGCWCG
+SAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25U
+aW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUWM2h0dHA6Ly93d3cuaXBz
+LmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGluZy5odG1sPzBABglghkgBhvhC
+AQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1lc3RhbXBp
+bmcuaHRtbDB/BgNVHR8EeDB2MDegNaAzhjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMy
+MDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFj
+ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEF
+BQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI
+hvcNAQEFBQADgYEAZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk3
+6MNbsMRnLWhasl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I
+3pGW7hdbrqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
@@ -2251,75 +1156,787 @@ mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
SnQ2+Q==
-----END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw
-OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu
-ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h
-gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K
-5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy
-9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE
-gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3
-eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs
-YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp
-aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp
-dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb
-sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB
-FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy
-f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W
-+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2
-uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf
-tXncwKJrMiE3lvgOOBITRzcahirLer4c
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa
-Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g
-eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND
-IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu
-QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui
-me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm
-RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/
-OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G
-O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF
-BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI
-KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh
-c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl
-cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw
-HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX
-hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV
-Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw
-6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF
-6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e
-Pr3WHV1wA7EY6oT4zBx+2gT9XBTB
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE
-ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE
-AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ
-BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT
-aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl
-KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX
-GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj
-93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+
-P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow
-ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g
-ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN
-W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB
-IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB
-ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA
-ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb
-MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv
-J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW
-pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J
-HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ==
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx
+MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O
+isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY
+78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9
+zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd
+BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA
+Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN
+T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD
+mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy
+MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp
+eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg
+/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl
+wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh
+AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2
+PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu
+AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR
+MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc
+HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/
+Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
+f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO
+rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch
+6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3
+7CAFYd4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
+MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
+dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
+WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
+VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
+9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
+DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
+Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
+QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
+xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
+A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
+kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
+Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
+Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
+JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
+RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx
+MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG
+29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk
+oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk
+3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL
+qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN
+nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX
+ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H
+DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO
+TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
+kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w
+zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw
+ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU
+REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr
+2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s
+2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU
+GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj
+dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r
+TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB
+AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv
+c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl
+ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu
+MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
+T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud
+HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD
+VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny
+bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ
+J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG
+SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom
+JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO
+inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y
+caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB
+mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ
+YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9
+BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
+IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
+DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
+EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
+ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
+dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
+QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
+dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
+wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
+G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
+AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
+9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
+YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
+Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
+MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
+cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
+d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
+DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
+rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
+uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
+/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
+gQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
+dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
+bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
+BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
+IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
+bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
+Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
+Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
+ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
+KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN
+BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd
+BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN
+MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g
+Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG
+A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l
+c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT
+6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa
+Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL
+8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC
+9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ
+pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ
+CayJSdM=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
+rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
+Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
+Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
+BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
+dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
+AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
+YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
+hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
+L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
+SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
+1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
+6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
+Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
+aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
+7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
+xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
+rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
+eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
+USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
+lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
+T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
+BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
+dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
+HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
+KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
+5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
+kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
+AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
+HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
+AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
+mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
+4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
+81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
+Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
+NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
+VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
+bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
+H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
+4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
+BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
+EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
+FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
+lA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
+VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
+Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
+h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
+uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
+DzFc6PLZ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
+nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
+8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
+ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
+PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
+6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
+n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
+qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
+wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
+pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
+E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
+YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
+FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
+J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
+r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
+YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
+Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
+IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
+KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
+HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
+DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
+nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
+rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
+jBJ7xUS0rg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
+Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
+BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
+Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
+Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
+J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
+JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
+wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
+koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
+qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
+Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
+xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
+7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
+sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
+cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
+HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
+qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
+cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
+cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
+T8qAkbYp
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
+cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
+CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
+dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
+cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
+2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
+lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
+ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
+299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
+vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
+dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
+AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
+zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
+LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
+7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
+++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx
+DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2
+aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1
+MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT
+QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp
+b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX
+ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i
+/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU
+58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g
+halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E
+1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/
+ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb
+mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ
+kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN
+dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ
+ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn
+B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEwOTIzMTMxODE3WjB1MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQg
+LSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g
+5DY1Hw7hgCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZs
+jqBeynX8T90vFILqsY2K5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfH
+HB67Af+g7u0dEHdDW7lwy81MwFYxBTRy9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAEgfwwgfkwgfYGDSsGAQQB
+vj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3eXN0YXdp
+b255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2pp
+IGRsYSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENB
+IHcgaGllcmFyY2hpaSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3
+LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQw
+HwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQbsa8wHQYDVR0OBBYEFMODHtVZ
+d1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQBFIGh8Jpxt87A
+gSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy
+f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIis
+TsytFzVP32/W+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB
+3vSaoYg+wdkcvb6souMJzuc2uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U
+1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uftXncwKJrMiE3lvgOOBITRzcahirL
+er4c
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQ
+Q0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNaFw0xNzA0MTgxMjUzMDdaMHUxCzAJ
+BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMSQwIgYD
+VQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkNDIFNp
+Z25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCqgLJuQqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0g
+oBFAfntNU/QTKwSBaNuime7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2
+U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDImRoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8
+hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/OBRZp0uO1CSLcMcVJzyr
+2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0GO9f3/Ca5
+Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEA
+MIHDMHUGCCsGAQUFBwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2Vy
+dHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYIKwYBBQUHAgEWPmh0dHA6Ly93
+d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xhc2EyL3BjX3Bj
+YTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl
+cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE
+82AVXO08kMIwHQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3
+DQEBBQUAA4IBAQBWTsCbqXrXhBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM
+2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuVXo5u0WK8iaqATSyEVBhADHrPG6wY
+cLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw6P7pslxMWJBSNyQx
+aLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF6caa
+9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrW
+wBFjzz5ePr3WHV1wA7EY6oT4zBx+2gT9XBTB
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ
@@ -2348,200 +1965,116 @@ ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv
hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ
-TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg
-U2lnbmV0IC0gQ0EgS2xhc2EgMzEXMBUGA1UEBRMOTnVtZXIgd3Bpc3U6IDQwHhcN
-MDMxMDE0MTIwODAwWhcNMDgwNDI4MTA1MDU1WjB3MQswCQYDVQQGEwJQTDEfMB0G
-A1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBD
-ZXJ0eWZpa2FjamkgU2lnbmV0MSEwHwYDVQQDExhDQyBTaWduZXQgLSBPQ1NQIEts
-YXNhIDMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM/9GwvARNuCVN+PqZmO
-4FqH8vTqhenUyqRkmAVT4YhLu0a9AXeLAYVDu+NTkYzsAUMAfu55rIKHNLlm6WbF
-KvLiKKz4p4pbUr+ToPcwl/TDotidloUdBAxDg0SL+PmQqACZDe3seJho2IYf2vDL
-/G4TLMbKmNB0mlWFuN0f4fJNAgMBAAGjggGgMIIBnDAOBgNVHQ8BAf8EBAMCB4Aw
-EwYDVR0lBAwwCgYIKwYBBQUHAwkwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3
-dy5zaWduZXQucGwva3dhbGlmaWtvd2FuZS9yZXBvenl0b3JpdW0vY3JsL2tsYXNh
-My5jcmwwgdgGA1UdIASB0DCBzTCBygYOKwYBBAG+PwKCLAoCAQAwgbcwbAYIKwYB
-BQUHAgIwYBpeQ2VydHlmaWthdCB3eWRhbnkgemdvZG5pZSB6IGRva3VtZW50ZW0g
-IlBvbGl0eWthIENlcnR5ZmlrYWNqaSAtIENlcnR5ZmlrYXR5IHJlc3BvbmRlcm93
-IE9DU1AiLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5
-dG9yaXVtL2Rva3VtZW50eS9wY19vY3NwXzFfMC5wZGYwHwYDVR0jBBgwFoAUe2PM
-GZB6tM62O559bRUnUND5SbkwHQYDVR0OBBYEFG4jnCMvBALRQXtmDn9TyXQ/EKP+
-MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBACXrKG5Def5lpRwmZom3UEDq
-bl7y4U3qomG4B+ok2FVZGgPZti+ZgvrenPj7PtbYCUBPsCSTNrznKinoT3gD9lQQ
-xkEHwdc6VD1GlFp+qI64u0+wS9Epatrdf7aBnizrOIB4LJd4E2TWQ6trspetjMIU
-upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk
-GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug
-5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw
-OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu
-ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma
-M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+
-HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW
-Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9
-JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x
-W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC
-AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6
-IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z
-aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
-OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy
-bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE
-82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx
-UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan
-ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2
-2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV
-tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw
-OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu
-ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue
-Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA
-iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE
-OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db
-w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC
-3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
-AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC
-AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
-eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6
-IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z
-aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
-OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy
-bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM
-ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4
-7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG
-dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF
-JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz
-1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw
-OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v
-LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu
-ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks
-ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX
-REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D
-CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU
-YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP
-l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8
-MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz
-dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg
-Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg
-Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt
-L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf
-BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN
-AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI
-cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1
-CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW
-ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB
-KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE
-ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg
-U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX
-DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6
-IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg
-U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd
-uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v
-LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c
-ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w
-bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM
-MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH
-AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr
-YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC
-ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf
-MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO
-Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz
-+z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB
-vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
-IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
-IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
-Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
-BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
-MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
-ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
-CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
-8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
-zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
-fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
-w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
-G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
-epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
-laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
-QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
-fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
-YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
-ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
-gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
-MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
-IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
-dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
-czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
-dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
-aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
-AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
-b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
-ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
-nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
-18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
-gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
-Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
-sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
-SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
-CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
-GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
-zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
-omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
-IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
-IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
-Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS
-BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v
-cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9
-4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB
-Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J
-0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ
-FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx
-bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q
-SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb
-6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV
-m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g
-eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG
-kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7
-6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG
-CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc
-aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB
-gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w
-aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6
-tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0
-nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M
-77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV
-Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L
-ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM
-zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU
-rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF
-YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT
-oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu
-FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB
-0m6lG5kngOcLqagA
+MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg
+LSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7B
+rBlbN5maM5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRA
+spEXE4gvwb08ASY6w5s+HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8w
+nfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxWCeol9IekpBRVmuuSA6QG0Jkm+pGDJ05y
+j2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9JyN0ag1yII/LPx8HK5J4
+W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3xW20QjQcS
+ZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHk
+MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB
+Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo
+aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv
+cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
+OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev
+cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV
+HQ4EFgQUwGxGyl2CfpYHRonE82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1
+TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkxUGY7U9kVrLI71xBgoNVyzXTiMNDB
+vjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsanot1Xt6j0ZDC+03Fj
+LHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G22Ohu
++EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqW
+uHitKQDVtcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6
+NA9GRTCNxm/dXlcwnmY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg
+LSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3
+LanJtdueNe6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP
+6KZTU0DixOrV+K7iWaqAiQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6H
+dbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPEOpO94mAKcBUhk6T/ki0evXX/ZvvktwmF
+3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Dbw34hA1A+ckTwhxzecrB8
+TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC3P8QqoK4
+ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHk
+MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll
+IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB
+Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo
+aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv
+cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw
+OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev
+cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV
+HQ4EFgQUXvthcPHlH5BgGhlMErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIc
+e95Mvn710KCAISA0CuHD4aznTU6pLoCDShW47OR+GTpJUm1coTcUqlBHV9mra4VF
+rBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJGdsJF/XU/7smummgj
+MNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oFJTlp
+uxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1D
+OcePEhKz1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BX
+WCW+KxwiBrtQTXv4dTE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS
+b290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYwOTIxMTU0MjE5WjBxMQswCQYDVQQG
+EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb
+Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQg
+LSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNp
+ELfGW3KsARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq
+5c9epcGu+kg4a3BJChVXREl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5P
+LsUj3qwF78jUCQVckiiLVcnGfZtFCm+DCJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7
+lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luUYG/YDxTC4mqhRqfa4MnV
+O5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSPl+9k2fAU
+dchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0g
+BIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNl
+cnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0
+eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdp
+b255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEF
+BQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50
+eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf
+BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit
+5BZufZj2Tq3v8L3SgE34GOoIcdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDS
+PiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1CQk2JoKQJ6pyAf6xJBgWEIlm4RXE
+4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKWha0RJJxJgw/NyWpK
+G7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmABKK6o
+3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ
+TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu
+dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD
+QSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloXDTExMDkyMzExMTgxN1owdjELMAkG
+A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV
+BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0MgU2ln
+bmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJY
+rISEtSsduHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ1
+2FJarD1X6mSQ4cfN/60vLfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjR
+AM0tdwXSnzuTEunfw0Oup559y3Iqxg1cExflB6cfAgMBAAGjggGXMIIBkzBBBgNV
+HR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0v
+Y3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG
+AQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYB
+BQUHAgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVu
+dGVtICJQb2xpdHlrYSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5p
+ZSBjemFzZW0iLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVw
+b3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJfMS5wZGYwHwYDVR0jBBgwFoAU
+w4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavOYd9u9tej53vW
+XwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz
++z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMb
+skF8I31JxIeBvueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR
++7KtwMg4sFDJZ8RNgOf7tbA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDvjCCA3ygAwIBAgIFJQaThoEwCwYHKoZIzjgEAwUAMIGFMQswCQYDVQQGEwJG
@@ -2591,1179 +2124,1087 @@ NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R
0982gaEbeC9xs/FZTEYYKKuF0mBWWg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUF
-ADCBgTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3Rl
-cjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0
-ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJH
-QjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxm
-b3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09N
-T0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH+7uIzg3j
-Lz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/a
-N5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaa
-P+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC
-8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+DT+nHbrTUcEL
-pNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVIrLsm
-9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAO
-BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
-PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0
-aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5
-t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
-OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYm
-uNg4ON8qa90SzMc/RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjs
-LjBOlDW0JB9LeGna8gI4zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV
-8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38
-NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJF
-VTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMw
-IQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZ
-Q2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0z
-NzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1l
-cmZpcm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cu
-Y2hhbWJlcnNpZ24ub3JnMSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJj
-ZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVd
-GDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlUxFF6tdpg
-6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41
-XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxa
-UWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUM
-I/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyXroDclDZK9D7O
-NhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1UdEwEB
-/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFt
-YmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
-26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE
-AwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3Jn
-MCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
-VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8v
-Y3BzLmNoYW1iZXJzaWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJ
-KoZIhvcNAQEFBQADggEBAAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0n
-bJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tG
-fToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QU
-u/wNUPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZB
-zu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+
-S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfutGWaIZDgqtCYvDi1czyL
-+Nw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJF
-VTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMw
-IQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMX
-R2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcw
-OTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJm
-aXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNo
-YW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJv
-b3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCicKLQn0KuWxfH
-2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J1tPfnZda
-n5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH
-+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvu
-sZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8Co
-X6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWhz0hQpe/SyBoT
-+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/BAgw
-BgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJz
-aWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
-TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQD
-AgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5v
-cmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
-ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0
-dHA6Ly9jcHMuY2hhbWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3Qu
-aHRtbDANBgkqhkiG9w0BAQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVP
-MvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONG
-kyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76Svpyk
-BMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+
-xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLT
-BQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/AYoFWpO+ocH/+OcOZ6RH
-SXZddZAa9SaP8A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEF
-BQAwPTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQD
-ExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2
-MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZ
-BgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxv
-c0NXYKwzCkTsA18cgCSR5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi
-8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZVg2v7tK8R1fjeUl7NIknJITe
-sezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFOYFWe2yMZ
-eVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupd
-M5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUC
-AwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNV
-HQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4QgEBBAQDAgEG
-MDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29tL0NS
-TC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9W
-M2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
-yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzO
-UrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW
-2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
-//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4F
-TUcY1Rbpsda2ENW7l7+ijrRU
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUF
-ADBbMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUg
-VHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBD
-QSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNV
-BAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8G
-A1UECxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5
-WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzIDZBfZIGxqAgNTNj50wUoUrQB
-JcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCapCIlF3Po
-HuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKB
-Xy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvb
-UJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEITajV8fTXpLmaRcpPV
-MibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQFMAMBAf8wDgYD
-VR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3QuY29t
-MGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRw
-Oi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
-aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJ
-KoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99
-Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
-Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8
-smk/f3rPanTK+gQqnExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir4
-2NInPRmJX1p7ijvMDNpRrscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvk
-yCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6
-mis=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUF
-ADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAV
-BgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkz
-MDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qg
-Q28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdA
-wRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJ
-o6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHs
-Umu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTW
-MIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX
-69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/w
-Al0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
-HQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUA
-A4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/O
-EIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHR
-AosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
-R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJW
-FBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06Xyx
-V3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUF
-ADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
-VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1
-cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAw
-WjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
-VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1
-cmVkIElEIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWx
-KISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDX
-H+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNu
-RMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNs
-IumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcX
-xH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMBAAGjYzBhMA4G
-A1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF66Kv
-9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd
-823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
-dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthn
-gYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+
-fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
-8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwz
-Zr8TDRRu838fYxAe+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7m
-ULKn+gpFL6Lw8g==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUF
-ADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
-VQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9i
-YWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGEx
-CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
-EHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBS
-b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLe
-qKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOnTjC3U/dDxGkAV53ijSLdhwZA
-AIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5BmV/Sl0f
-vBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1
-GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3O
-FBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSii
-cNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8E
-BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm8KPi
-GxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJ
-KoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
-hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV
-5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBA
-I+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
-UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDA
-GySj4dzp30d8tbQkCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWV
-bd4=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUF
-ADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
-VQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdo
-IEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTEx
-MDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
-YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNl
-cnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAMbM5XPm+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRn
-ogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1x
-kX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9
-vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlK
-V9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5
-OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4
-S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w
-HQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+
-w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehD
-LI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VH
-MWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
-mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E
-1CAx2/S6cCZdkGCevEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN
-7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UE
-BhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5l
-bnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEf
-MB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50
-cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIw
-MjM0MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
-Ew1FbnRydXN0LCBJbmMuMTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BT
-IGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAy
-MDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9vdCBDZXJ0
-aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZm
-Lk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypo
-wCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9KlmaI5UXLEWe
-H25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68j6xS
-lkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94Dk
-Zfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
-sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAE
-JDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSME
-GDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
-hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0G
-CSqGSIb3DQEBBQUAA4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW
-+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ
-47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p
-8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE
-2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDN
-tGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/
-WrQ8
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMC
-RVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNV
-BAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9u
-YWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9m
-ZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCB
-nTELMAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJj
-ZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZp
-cm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYX
-Y2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
-DwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8
-c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9Z
-pTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx
-/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPayBQC6haD9HThu
-y1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8NeTv
-tjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMB
-AAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv
-bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDEx
-MDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAd
-BgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD
-ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/Gz
-R0iLjJcG1+p+o1wqu00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvX
-wOaD7FnMP97/T2u3Z36mhoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6nt
-Bas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZ
-dBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/g
-e9YGVM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJV
-UzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
-R2xvYmFsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBE
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UE
-AxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
-DwAwggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6Csgncbz
-YEbYwbLVjDHZ3CB5JIG/NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96x
-PqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1kLUCgsBDTOEhGiKEMuzozKmKY
-+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFAVvqgx306
-E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdL
-Fnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMB
-AAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266
-ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUapEBVYIAUJMA4G
-A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7srJe
-rJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/Ngd
-RN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
-A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/q
-kZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa
-4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
-H4z1Ir+rzoPz4iIprn2DQKi6bA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUF
-ADBYMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8G
-A1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
-eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYT
-AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVz
-dCBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHW
-AVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9ju
-apYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9nceJSOC7
-KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5
-X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7W
-inXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s
-0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZIhvcN
-AQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CeP
-bJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
-4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aV
-Il6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJly
-c1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
-1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJV
-UzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3Qg
-VW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFow
-RTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNV
-BAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
-ggIPADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckU
-HUWCq8YdgNY96xCcOq9tJPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430
-SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw
-8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs7tqqhZJm
-r/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD
-/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBO
-U5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xdVHppCZbW2xHBjXWo
-tM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCXteGYO8A3ZNY9
-lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hBZ3Ki
-KN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9F
-i1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
-nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1Ud
-EwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8G
-A1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
-hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIaw
-C/yOsjmPRFWrZIRcaanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv
-9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7
-/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDV
-nVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG
-8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxr
-u18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2Hr
-rDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKWkoRepqO1pD4r2czYG0eq
-8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslKxfMnZmaG
-rGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9
-fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6
-ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJV
-UzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3Qg
-VW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAw
-WjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4G
-A1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6Gq
-dHtXr0om/Nj1XqduGdt0DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQw
-Ax5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC
-5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8QJqVJwy7X
-QYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw7
-6L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC
-9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IEr
-KIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73y/Zl92zxlfgC
-OzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAnZqzw
-cEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgf
-ksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
-Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAP
-BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQ
-KzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
-BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7
-WJtAJDday6sWSf+zdXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4s
-NcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjg
-AA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo
-4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEn
-cKpqA1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2R
-LrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8
-mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m1wk8OhwRDqZsN/etRIcs
-KMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7dFGdTbHFc
-JoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9
-VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSL
-akhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEg
-MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkds
-b2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAw
-WhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3Qg
-Q0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
-U2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8o
-mUVCxKs+IVSbC9N/hHD6ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe
-+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1
-AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5
-TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo
-4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99y
-qWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IHV2ccHsBqBt5Z
-tJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxz
-aWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0
-mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
-J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4
-h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRD
-LenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
-9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmg
-QWpzU/qlULRuJQ/7TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq
-/H5COEBkEveegeGTLg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV
-UzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQL
-EyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
-DTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMx
-ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMo
-R28gRGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAw
-DQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d
-/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9
-S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32qRe3H3I2
-TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVl
-OARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFA
-pMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44
-dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLEsNKR1EwRcbNh
-yz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2oatTj
-oWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdy
-b3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
-BQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYX
-MP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
-I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheab
-IZ0KbIIOqPjCDPoQHmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzr
-Tia2cyvk0/ZM/iZx4mERdEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBD
-pqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/bvZ8=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMC
-SFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96
-YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9r
-MTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZh
-bnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQsw
-CQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExv
-Y2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZh
-bnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sgVXpsZXRpIChDbGFzcyBCKSBU
-YW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx
-6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp
-2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5
-sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4IC
-nzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAAYwEQYJ
-YIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxF
-TSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3Mg
-U3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
-bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5l
-dExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGku
-IEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg
-YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBl
-bGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIElu
-dGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2Rv
-Y3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5u
-ZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQg
-dGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhl
-IE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2Nr
-Lm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
-CSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM43WIEJes
-sDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w
-2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgB
-azMpUIaD8QFI
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMC
-SFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96
-YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9r
-MTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0
-dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsx
-CzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0
-TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
-dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9jayBFeHByZXNzeiAoQ2xhc3Mg
-QykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qd
-QPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64
-gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEA
-AaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0PAQH/BAQDAgAG
-MBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJNRklH
-WUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxh
-bm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
-b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQg
-YSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2
-ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0
-ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4g
-QXogZWxqYXJhcyBsZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0
-LiBJbnRlcm5ldCBob25sYXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5l
-dC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxv
-Y2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2Ug
-YW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRv
-IHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0
-bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQgY3BzQG5ldGxvY2submV0
-LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2xJZIwVzN
-mtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5N
-NwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeA
-yNDYpQcCNJgEjTME1A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYT
-AkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUG
-A1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQL
-ExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5
-em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0
-N1oXDTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdI
-dW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBI
-YWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtp
-YWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBBKSBU
-YW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbb
-O51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QV
-Or/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8WgD/qaiYdPv2
-LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7tqyF
-/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCub
-MvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
-ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZI
-AYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEg
-RXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
-bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFw
-amFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
-Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEg
-ZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXog
-ZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGph
-cmFzIGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVy
-bmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3Mg
-Y2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQg
-ZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl
-IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5l
-dExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5l
-dC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqG
-SIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
-xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoU
-MaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJ
-MSEN1rUQQeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+u
-xdAu6tYPVuxkf1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q
-5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMC
-SFUxETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96
-YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9r
-MUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xh
-c3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9A
-bmV0bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJ
-MQswCQYDVQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5l
-dExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNp
-dHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0dCBLb3pq
-ZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3
-DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ul
-ZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQer7C8HORSjKAy
-r7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhbm+1b
-OdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrq
-OU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
-mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9
-o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYw
-ggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2
-YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBT
-emFiYWx5emF0YWJhbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0
-LiBBIG1pbm9zaXRldHQgZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMg
-ZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0
-ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJh
-biwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9p
-cnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1
-bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3dy5uZXRsb2NrLmh1L2Rv
-Y3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2NrLm5ldCBl
-LW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVz
-ZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRM
-b2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5l
-dGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
-ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEB
-BQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufA
-QTPGtpvQMznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68
-d4bDBsxafEp+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yf
-uqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSj
-nLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR
-5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMC
-Qk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1Zh
-ZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNa
-MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRsw
-GQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4Gt
-Mh6QRr+jhiYaHv5+HBg6XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst
-/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yklvc/ulsrHHo1wtZn/qtmUItt
-KGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbBlDePSHFj
-IuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRc
-AitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJl
-cZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2
-BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIizPtGo/KPaHbDR
-sSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOhD7os
-FRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR
-7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
-yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8G
-A1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwz
-JQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
-a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0
-ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcN
-AQEFBQADggIBAD4KFk2fBluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJ
-RqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQty
-U/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgt
-JodmVjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUs
-fU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1
-O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozchLsib9D45MY56QSIPMO6
-61V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1WVaj+ahJ
-efivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1
-B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6y
-hhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOT
-HcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
+b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
+MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
+ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
+IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
+AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
+unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
+BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
+7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
+0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
+roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
+A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
+aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
+26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
+BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
+EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
+BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
+AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
+p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
+1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
+XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
+eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
+tGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
+YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
+MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
+NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
+A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
+A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
+Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
+QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
+eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
+B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
+z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
+AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
+ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
+TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
+MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
+VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
+VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
+AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
+bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
+ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
+VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
+ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
+AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
+PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
+cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
+MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
+IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
+ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
+VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
+kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
+EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
+H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
+HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
+QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
+Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
+AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
+yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
+FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
+ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
+kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
+ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
+MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
+VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
+FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
+ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
+gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
+fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
+ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
+ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
+c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
+dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
+aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
+hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
+QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
+h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
+rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
+9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u
+Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY
+rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z
+hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay
+BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL
+iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb
+AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv
+bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0
+MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E
+FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n
+VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq
+u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m
+hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl
+ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp
+QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5
+quGnM/b9Sh/22WA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD
+EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz
+aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w
+MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l
+dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh
+bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq
+eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe
+r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5
+3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd
+vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
+mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC
+wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg
+hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0
+TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg
+ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg
+dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6
+b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl
+c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0
+ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3
+dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu
+ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo
+ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3
+Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
+ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA
+A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ
+MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+
+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR
+VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY
+83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3
+macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMC
-Qk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1Zh
-ZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRa
-MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRsw
-GQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTP
-krgEQK0CSzGrvI2RaNggDhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9
-cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOijKTVopAFPD6QuN+8bv+OPEKhy
-q1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79KDDRMpsMh
-vVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRl
-lDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+
-pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJ
-k8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjcT5EOE7zelaTf
-i5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEXMJPp
-Govgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6ts
-gLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
-4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEw
-DwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMw
-gcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
-YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJv
-b3QgQ0EgMyBDZXJ0aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFBy
-YWN0aWNlIFN0YXRlbWVudC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVv
-dmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLA
-E+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1
-XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMg
-TGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkq
-hkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM07ucp2sNbtrCD2dDQ4iH7
-82CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+shvzuXYO8
-BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM
-3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hR
-OJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54C
-rnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
-DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPs
-MZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmi
-oHfRMJ6szHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRe
-cCocIdiP4b0jWy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEo
-kt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+
-ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUF
-ADBIMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9y
-YXRpb24xFzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzEx
-OFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1Nl
-Y3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBD
-QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7C
-T8rU4niVWJxB4Q2ZQCQXOZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/je
-p4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9tDWccV9cGrcrI9f4Or2YlSASW
-C12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uHGFaAJsTQ
-3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobv
-omuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcW
-NFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIE
-Bh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYjaHR0
-cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUB
-BAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
-6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s
-7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cp
-rp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
-nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZG
-BlSm8jIKYyYwa5vR3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShL
-HZ4swrhovO0C7jE=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUF
-ADBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9y
-YXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0
-MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMX
-U2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9i
-YWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxV
-aQZx5RNoJLNP2MwhR/jxYDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7H
-fAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQbqR8JNGuQsiWUGMu4P51/pin
-X0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g8NEXLJXr
-9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz
-+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvU
-d+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGC
-NxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
-VR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAnoCWG
-I2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQB
-gjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
-URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X
-+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895
-P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
-3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNsp
-nWzFacxHVaIw98xcf8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJP
-Ix/abKwfROHdI3hRW8cW
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJV
-UzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
-A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQG
-EwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEy
-MDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGm
-BIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1
-KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZJRRU6ybH
-838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4Q
-yDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmC
-uDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W
-93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0GA1UdDgQWBBS/
-X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0fhvRb
-Vazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJm
-aWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
-bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMB
-Af8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1ep
-oXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
-PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L
-7ShZ3U0WixeDyLJlxy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMt
-lb71cZBDzI0fmgAKhynpVSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl9
-0TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/
-D5fs4C8fF5Q=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJ
-TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp
-Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20g
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYw
-OTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g
-THRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2ln
-bmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDBiNsJvGxGfHif
-lXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1yo4UcodM9
-tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1
-YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srh
-JosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d
-5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNiHzvEvqBTViVs
-UQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z6+hs
-TXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2Oq
-qGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
-Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3v
-wmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOz
-EmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
-37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMC
-Aa4wHQYDVR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFsw
-LKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3Js
-MCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3Js
-MIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYB
-BQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUG
-CCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRp
-YXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3RhcnQgQ29tbWVyY2lhbCAo
-U3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5LCByZWFk
-IHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0
-Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUg
-YXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZI
-AYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
-TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEA
-FmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArex
-mvclmAk8jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPle
-WKYK34wGmkUWFjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8
-rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNm
-ezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
-fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZ
-tWgo+2EuvoSoOMCZEoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0
-yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+PwqyvqCUqDvr0tVk+vBtfAii6w0TiYi
-BKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl1njFmUNj403g
-dy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/
-7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/Fl
-UQqmMGqz9IgcgA38corog14=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMC
-SUwxDzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoT
-DVN0YXJ0Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkw
-JwYDVQQDEyBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8G
-CSqGSIb3DQEJARYSYWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0
-OFoXDTM1MDMxMDE3Mzc0OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJ
-c3JhZWwxDjAMBgNVBAcTBUVpbGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQu
-MRowGAYDVQQLExFDQSBBdXRob3JpdHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBT
-U0wgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmFk
-bWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
-7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x18LEwrHkllbEvqoUDufM
-OlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5yYPo7QAPyHWlLzRM
-GOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYILzUCAwEAAaOC
-AjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0GA1UdDgQW
-BBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOWzL3+
-MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT
-BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0
-ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVl
-IFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
-YWRtaW5Ac3RhcnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0
-Y29tLm9yZzAdBgNVHRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZI
-AYb4QgEBBAQDAgAHMC8GCWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eTAyBglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQu
-c3RhcnRjb20ub3JnL2NhLWNybC5jcmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6
-Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJYIZIAYb4QgEIBCwWKmh0dHA6Ly9j
-ZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/YXBwPTExMTANBgkqhkiG9w0B
-AQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1ct8nV0t2hPdopP7rPwl+
-KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p00UOpO6wNnQt8M2Y
-I3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLbcCOxgN8aIDjn
-fg==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJ
-BgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3
-aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1
-MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFH
-MR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG
-9w0BAQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJC
-Eyq8ZVeCQD5XJM1QiyUqt2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9
-lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtr
-vxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpgvd21mWRT
-uKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbL
-tK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpK
-xVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdV
-xVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02yMszYF9rNt85m
-ndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkOpeUD
-DniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59
-je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
-gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOB
-rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
-OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEF
-BQcCARYgaHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZI
-hvcNAQEFBQADggIBACe645R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhW
-fvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g
-7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8
-AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS
-2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5
-JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a77KwPJ+HbBIrZXAVUjEa
-JM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJkvC24JdVU
-orgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7X
-dVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG
-2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEB
-nunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
+MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
+cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
+Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
+0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
+wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
+7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
+8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
+BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
+JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
+6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
+3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
+D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
+CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx
+MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg
+Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ
+iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa
+/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ
+jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI
+HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7
+sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w
+gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw
+KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG
+AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
+URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO
+H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm
+I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
+iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx
+DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0
+Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
+YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0
+OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp
+bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp
+dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x
+18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5
+yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI
+LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G
+A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW
+zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT
+BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x
+GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh
+cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV
+HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G
+CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy
+BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j
+cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ
+YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/
+YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1
+ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p
+00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb
+cCOxgN8aIDjnfg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkG
-A1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dp
-c3NTaWduIFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYx
-MDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWdu
-IEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIw
-DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZc
-ZB/HL37PZ/pEQtZ2Y5Wu669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeT
-IsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UFeNSH2XFwMyVTtIc7KZAoNppV
-RDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kneWCqv9hbr
-S3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky
-6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4E
-LE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/Q
-KTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrYzt3oEBSa/m0j
-h26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjydomy
-ExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3
-HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW
-ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGeP
-AgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
-HQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv
-zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4w
-LAYIKwYBBQUHAgEWIGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20v
-MA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfF
-wUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQX
-OHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vl
-pqD4U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/Fqd
-Oxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cb
-OQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8DYSjFyMsSoEJL+WuICI20
-MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1BaYEUtLS1
-7Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyII
-oK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0Ne
-bvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsy
-mxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
+MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu
+IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw
+WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD
+ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y
+IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn
+IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+
+6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob
+jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw
+izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl
++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY
+zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP
+pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF
+KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW
+ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB
+AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0
+ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA
+A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0
+uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+
+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7
+jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/
+u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D
+YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1
+puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa
+icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG
+DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
+kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkG
-A1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dp
-c3NTaWduIFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAy
-NTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBB
-RzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkq
-hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dO
-cbpLj6VzHVxumK4DV644N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gRE
-pzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm+/pe7R20nqA1W6GSy/BJkv6F
-CgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH6INaUFjp
-iou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2
-kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aD
-Cyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jM
-qDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJMoBgs5PAKrYY
-C51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBsROop
-N4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFu
-sB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
-5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEA
-AaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
-tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggr
-BgEFBQcCARYgaHR0cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJ
-KoZIhvcNAQEFBQADggIBAHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ
-1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEG
-DyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcS
-H9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpH
-kXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE
-790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8aRl5xB9+lwW/xekkUV7U
-1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqPe97Dh4kQ
-mUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNV
-V4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29
-MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm
-0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUF
-ADBkMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
-HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNz
-Y29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBa
-MGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMc
-RGlnaXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Nj
-b20gUm9vdCBDQSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
-0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJ
-kCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyFNDhhSbEA
-n9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj
-/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxz
-h+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJ
-vbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBuHYwadzVcFh4r
-Ux80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbNcA78
-yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AO
-eCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC
-L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoI
-lmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p
-/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
-HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYB
-Af8CAQcwHwYDVR0jBBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0O
-BBYEFAMlL95vggE6XCzcK6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1
-EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734e
-dAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzn
-eAXQMbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXb
-D8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrE
-qdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsRls/bxig5OgjOR1tTWsWZ
-/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascClOS5cfGni
-LLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFb
-jCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBa
-ZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZh
-vnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
-zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E
-0F/6MBr1mmz0DlP5OlvRHA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2
-VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xh
-ecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYD
-VQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
-QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1
-MTMxMDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RS
-VVNUIEVsZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFz
-xLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZBTktBUkExVjBUBgNVBAoMTShj
-KSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9p
-bSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9
-InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1
-cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35JYbOG7E6mQW6E
-vAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ8y1U
-iBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm
-5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51
-b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IB
-AQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd
-82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
-q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oS
-N7wBGjSFvW5P55FyB0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8
-KsF8kOipKMDTkcatKIdAaLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq0
-7Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2
-VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xh
-ecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYD
-VQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0g
-R8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUw
-HhcNMDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2
-VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xh
-ecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYD
-VQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0g
-R8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjH
-WHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9
-irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdhR3n9wFHxwZnn
-3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2gQrSd
-iVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHps
-mxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p
-zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Z
-z58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMB
-Af8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
-Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWo
-lKMiVW4XSf/SKfE4Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbc
-oCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4
-nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsg
-OqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9R
-nuk5UrbnBEI=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUF
-ADA/MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIw
-NTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN8
-6aXfTEc2pBsBHH8eV4qNw8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UK
-IXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/
-cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O1RGvqa/l
-mr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq
-16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdL
-iYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUq
-dULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FCVGqY8A2tl+lS
-XunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1tB6iE
-fC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKX
-TiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN
-Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0G
-A1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkG
-BGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
-09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2
-WPWus4MzeKR6dBcZTulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2Jyf
-tB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3gh
-qMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKb
-xkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1
-AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephg
-IqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7m
-XQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6MmnD+iMsJKxYEYMRBWqoTv
-LQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk7tfGOB5j
-GxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJI
-oRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v
-3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYs
-fPQS
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUF
-ADCByjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8w
-HQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykg
-MjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
-MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcN
-MzYwNzE2MjM1OTU5WjCByjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlT
-aWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTow
-OAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
-emVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1Ymxp
-YyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8
-RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs
-70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pS
-S9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+Q
-ueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
-rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMK
-z10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
-Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0
-cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/T
-ZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP
-2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGq
-CBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU
-7qKEKQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqV
-ir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4o
-tp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8NhnacRHr2lVz2XTIIM6RU
-thg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
-BhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBG
-YXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMg
-RmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0
-MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoT
-C1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0
-aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0
-aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mXx3Oqfz1c
-QJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93O
-vRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjB
-qAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43
-YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCEAQgAFG5Uhpq6
-zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGjYTBf
-MA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAy
-MDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw
-b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7k
-uxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZW
-ohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R
-OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zk
-r8QA1dhYJPz1j+zxx32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01
-QIroTmMatukgalHizqSQ33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ
-1dZPIWU7Sn9Ho/s=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUF
-ADCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5
-LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0w
-KwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
-HhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMC
-VVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMb
-WFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBH
-bG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEB
-AQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwuIR1cRN8h
-XX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9K
-mHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavn
-HTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3
-hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRaJSKNNCyy9mgd
-Em3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvryxS3T
-/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQD
-AgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
-jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1
-cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcN
-AQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
-/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYS
-Nrsf16GBBEYgoyxtqZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT
-5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGP
-urt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd
-50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUF
-ADCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYG
-A1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UE
-CxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYx
-MTE3MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTAT
-BgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
-ZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0
-ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQ
-LZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29
-dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk6KHYcWUNo1F7
-7rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/KaAcd
-HJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR3
-2HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7
-W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7OR
-tvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
-uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQ
-aEfZYGDm/Ac9IiAXxPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqd
-E8hhuvU5HIe6uL17In/2/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+
-MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+
-fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE
-ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z
-dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq
-hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDMwMTE1MTYyOTE3
-WhcNMDcwMTE0MTYyOTE3WjCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh
-bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g
-dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEgMB4GA1UE
-AxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEWFmhvc3Rt
-YXN0ZXJAc3BpLWluYy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPB6
-rdoiLR3RodtM22LMcfwfqb5OrJNl7fwmvskgF7yP6sdD2bOfDIXhg9852jhY8/kL
-VOFe1ELAL2OyN4RAxk0rliZQVgeTgqvgkOVIBbNwgnjN6mqtuWzFiPL+NXQExq40
-I3whM+4lEiwSHaV+MYxWanMdhc+kImT50LKfkxcdAgMBAAGjggEfMIIBGzAdBgNV
-HQ4EFgQUB63oQR1/vda/G4F6P4xLiN4E0vowgesGA1UdIwSB4zCB4IAUB63oQR1/
-vda/G4F6P4xLiN4E0vqhgcSkgcEwgb4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdJ
-bmRpYW5hMRUwEwYDVQQHEwxJbmRpYW5hcG9saXMxKDAmBgNVBAoTH1NvZnR3YXJl
-IGluIHRoZSBQdWJsaWMgSW50ZXJlc3QxEzARBgNVBAsTCmhvc3RtYXN0ZXIxIDAe
-BgNVBAMTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo
-b3N0bWFzdGVyQHNwaS1pbmMub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
-AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW
-iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms
-1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY=
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk
+MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg
+Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT
+AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp
+Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9
+m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih
+FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/
+TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F
+EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco
+kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu
+HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF
+vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo
+19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC
+L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW
+bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX
+JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw
+FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc
+K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf
+ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik
+Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB
+sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e
+3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR
+ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip
+mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH
+b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf
+rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms
+hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
+zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6
+MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg
+MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8
+dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz
+MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy
+dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD
+VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg
+xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu
+xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7
+XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k
+heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J
+YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C
+urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1
+JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51
+b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV
+9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7
+kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh
+fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
+B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA
+aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS
+RGQDJereW26fyfJOrN3H
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS
+S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
+SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3
+WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv
+bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU
+UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw
+bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe
+LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef
+J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh
+R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ
+Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX
+JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p
+zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S
+Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq
+ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz
+gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH
+uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS
+y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/
+MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow
+PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR
+IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q
+gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy
+yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts
+F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2
+jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx
+ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC
+VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK
+YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH
+EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN
+Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud
+DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE
+MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK
+UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf
+qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK
+ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE
+JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7
+hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1
+EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm
+nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX
+udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz
+ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe
+LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl
+pYYsfPQS
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v
+dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0
+MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww
+KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G
+A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13
+5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE
+SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O
+JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu
+ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE
+AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB
+AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB
+CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw
+b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo
+7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/
+0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7
+nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx
+x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ
+33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD
@@ -3833,7 +3274,6 @@ IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
Cm26OWMohpLzGITY+9HPBVZkVw==
-----END CERTIFICATE-----
-
-----BEGIN CERTIFICATE-----
MIIGJDCCBY2gAwIBAgIEQoaroDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
@@ -3895,22 +3335,3 @@ xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9
e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu
glmQ1A==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
-dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
-MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
-dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
-BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
-cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
-MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
-aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
-ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
-IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
-1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f41f4b7382..6d80a21483 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,13094 +1,13143 @@
-<?xml version="1.0" ?>
-<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="llsd.xsd">
-<map>
- <key>CrashHostUrl</key>
- <map>
- <key>Comment</key>
- <string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>AFKTimeout</key>
- <map>
- <key>Comment</key>
- <string>Time before automatically setting AFK (away from keyboard) mode (seconds, 0=never).
- Valid values are: 0, 120, 300, 600, 1800</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>300</real>
- </map>
- <key>AdminMenu</key>
- <map>
- <key>Comment</key>
- <string>Enable the debug admin menu from the main menu. Note: This will just allow the menu to be shown; this does not grant admin privileges.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ActiveFloaterTransparency</key>
- <map>
- <key>Comment</key>
- <string>Transparency of active floaters (floaters that have focus)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.95</real>
- </map>
- <key>AdvanceSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Display advanced parameter settings in snaphot interface</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AgentPause</key>
- <map>
- <key>Comment</key>
- <string>Ask the simulator to stop updating the agent while enabled</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AlertedUnsupportedHardware</key>
- <map>
- <key>Comment</key>
- <string>Set if there's unsupported hardware and we've already done a notification.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AllowMultipleViewers</key>
- <map>
- <key>Comment</key>
- <string>Allow multiple viewers.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AllowTapTapHoldRun</key>
- <map>
- <key>Comment</key>
- <string>Tapping a direction key twice and holding it down makes avatar run</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AnimateTextures</key>
- <map>
- <key>Comment</key>
- <string>Enable texture animation (debug)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AnimationDebug</key>
- <map>
- <key>Comment</key>
- <string>Show active animations in a bubble above avatars head</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AppearanceCameraMovement</key>
- <map>
- <key>Comment</key>
- <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ApplyColorImmediately</key>
- <map>
- <key>Comment</key>
- <string>Preview selections in color picker immediately</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ApplyTextureImmediately</key>
- <map>
- <key>Comment</key>
- <string>Preview selections in texture picker immediately</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ArrowKeysAlwaysMove</key>
- <map>
- <key>Comment</key>
- <string>While cursor is in chat entry box, arrow keys still control your avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AskedAboutCrashReports</key>
- <map>
- <key>Comment</key>
- <string>Turns off dialog asking if you want to enable crash reporting</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AuctionShowFence</key>
- <map>
- <key>Comment</key>
- <string>When auctioning land, include parcel boundary marker in snapshot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AudioLevelAmbient</key>
- <map>
- <key>Comment</key>
- <string>Audio level of environment sounds</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelDoppler</key>
- <map>
- <key>Comment</key>
- <string>Scale of doppler effect on moving audio sources (1.0 = normal, &lt;1.0 = diminished doppler effect, &gt;1.0 = enhanced doppler effect)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AudioLevelMaster</key>
- <map>
- <key>Comment</key>
- <string>Master audio level, or overall volume</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AudioLevelMedia</key>
- <map>
- <key>Comment</key>
- <string>Audio level of Quicktime movies</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelMic</key>
- <map>
- <key>Comment</key>
- <string>Audio level of microphone input</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AudioLevelMusic</key>
- <map>
- <key>Comment</key>
- <string>Audio level of streaming music</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelRolloff</key>
- <map>
- <key>Comment</key>
- <string>Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AudioLevelSFX</key>
- <map>
- <key>Comment</key>
- <string>Audio level of in-world sound effects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelUI</key>
- <map>
- <key>Comment</key>
- <string>Audio level of UI sound effects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelVoice</key>
- <map>
- <key>Comment</key>
- <string>Audio level of voice chat</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioLevelWind</key>
- <map>
- <key>Comment</key>
- <string>Audio level of wind noise when standing still</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>AudioStreamingMedia</key>
- <map>
- <key>Comment</key>
- <string>Enable streaming</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AudioStreamingMusic</key>
- <map>
- <key>Comment</key>
- <string>Enable streaming audio</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AuditTexture</key>
- <map>
- <key>Comment</key>
- <string>Enable texture auditting.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoAcceptNewInventory</key>
- <map>
- <key>Comment</key>
- <string>Automatically accept new notecards/textures/landmarks</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoLeveling</key>
- <map>
- <key>Comment</key>
- <string>Keep Flycam level.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AutoLoadWebProfiles</key>
- <map>
- <key>Comment</key>
- <string>Automatically load ALL profile webpages without asking first.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoLogin</key>
- <map>
- <key>Comment</key>
- <string>Login automatically using last username/password combination</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoMimeDiscovery</key>
- <map>
- <key>Comment</key>
- <string>Enable viewer mime type discovery of media URLs</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoPilotLocksCamera</key>
- <map>
- <key>Comment</key>
- <string>Keep camera position locked when avatar walks to selected position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutoSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Update snapshot when camera stops moving, or any parameter changes</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AutomaticFly</key>
- <map>
- <key>Comment</key>
- <string>Fly by holding jump key or using "Fly" command (FALSE = fly by using "Fly" command only)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AvalinePhoneSeparator</key>
- <map>
- <key>Comment</key>
- <string>Separator of phone parts to have Avaline numbers human readable in Voice Control Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>-</string>
- </map>
- <key>AvatarAxisDeadZone0</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 0 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisDeadZone1</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 1 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisDeadZone2</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 2 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisDeadZone3</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 3 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisDeadZone4</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 4 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisDeadZone5</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 5 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>AvatarAxisScale0</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 0 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarAxisScale1</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 1 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarAxisScale2</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 2 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarAxisScale3</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 3 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarAxisScale4</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 4 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarAxisScale5</key>
- <map>
- <key>Comment</key>
- <string>Avatar axis 5 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>AvatarBacklight</key>
- <map>
- <key>Comment</key>
- <string>Add rim lighting to avatar rendering to approximate shininess of skin</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AvatarFeathering</key>
- <map>
- <key>Comment</key>
- <string>Avatar feathering (less is softer)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>16.0</real>
- </map>
- <key>AvatarPickerSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>AvatarPickerURL</key>
- <map>
- <key>Comment</key>
- <string>Avatar picker contents</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>AvatarBakedTextureUploadTimeout</key>
- <map>
- <key>Comment</key>
- <string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>60</integer>
- </map>
- <key>AvatarBakedLocalTextureUpdateTimeout</key>
- <map>
- <key>Comment</key>
- <string>Specifes the maximum time in seconds to wait before updating your appearance during appearance mode.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>AvatarPhysics</key>
- <map>
- <key>Comment</key>
- <string>Enable avatar physics.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AvatarPhysicsTest</key>
- <map>
- <key>Comment</key>
- <string>Simulate continuous physics behavior on all nearby avatars.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AvatarSex</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>BackgroundYieldTime</key>
- <map>
- <key>Comment</key>
- <string>Amount of time to yield every frame to other applications when SL is not the foreground window (milliseconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>40</integer>
- </map>
- <key>BottomPanelNew</key>
- <map>
- <key>Comment</key>
- <string>Enable the new bottom panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BrowserHomePage</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://www.secondlife.com</string>
- </map>
- <key>BrowserIgnoreSSLCertErrors</key>
- <map>
- <key>Comment</key>
- <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BlockAvatarAppearanceMessages</key>
- <map>
- <key>Comment</key>
- <string>Ignores appearance messages (for simulating Ruth)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BlockSomeAvatarAppearanceVisualParams</key>
- <map>
- <key>Comment</key>
- <string>Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BrowserProxyAddress</key>
- <map>
- <key>Comment</key>
- <string>Address for the Web Proxy]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>BrowserProxyEnabled</key>
- <map>
- <key>Comment</key>
- <string>Use Web Proxy</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BrowserProxyExclusions</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>BrowserProxyPort</key>
- <map>
- <key>Comment</key>
- <string>Port for Web Proxy</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3128</integer>
- </map>
- <key>BrowserProxySocks45</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>BuildAxisDeadZone0</key>
- <map>
- <key>Comment</key>
- <string>Build axis 0 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisDeadZone1</key>
- <map>
- <key>Comment</key>
- <string>Build axis 1 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisDeadZone2</key>
- <map>
- <key>Comment</key>
- <string>Build axis 2 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisDeadZone3</key>
- <map>
- <key>Comment</key>
- <string>Build axis 3 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisDeadZone4</key>
- <map>
- <key>Comment</key>
- <string>Build axis 4 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisDeadZone5</key>
- <map>
- <key>Comment</key>
- <string>Build axis 5 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>BuildAxisScale0</key>
- <map>
- <key>Comment</key>
- <string>Build axis 0 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildAxisScale1</key>
- <map>
- <key>Comment</key>
- <string>Build axis 1 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildAxisScale2</key>
- <map>
- <key>Comment</key>
- <string>Build axis 2 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildAxisScale3</key>
- <map>
- <key>Comment</key>
- <string>Build axis 3 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildAxisScale4</key>
- <map>
- <key>Comment</key>
- <string>Build axis 4 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildAxisScale5</key>
- <map>
- <key>Comment</key>
- <string>Build axis 5 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>BuildFeathering</key>
- <map>
- <key>Comment</key>
- <string>Build feathering (less is softer)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>16.0</real>
- </map>
- <key>BulkChangeIncludeAnimations</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect animations</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeBodyParts</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect body parts</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeClothing</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect clothing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeGestures</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect gestures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeNotecards</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect notecards</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeObjects</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeScripts</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect scripts</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeSounds</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect sounds</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeIncludeTextures</key>
- <map>
- <key>Comment</key>
- <string>Bulk permission changes affect textures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BulkChangeEveryoneCopy</key>
- <map>
- <key>Comment</key>
- <string>Bulk changed objects can be copied by everyone</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BulkChangeNextOwnerCopy</key>
- <map>
- <key>Comment</key>
- <string>Bulk changed objects can be copied by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BulkChangeNextOwnerModify</key>
- <map>
- <key>Comment</key>
- <string>Bulk changed objects can be modified by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BulkChangeNextOwnerTransfer</key>
- <map>
- <key>Comment</key>
- <string>Bulk changed objects can be resold or given away by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>BulkChangeShareWithGroup</key>
- <map>
- <key>Comment</key>
- <string>Bulk changed objects are shared with the currently active group</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ButtonFlashCount</key>
- <map>
- <key>Comment</key>
- <string>Number of flashes after which flashing buttons stay lit up</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>8</integer>
- </map>
- <key>ButtonFlashRate</key>
- <map>
- <key>Comment</key>
- <string>Frequency at which buttons flash (hz)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.25</real>
- </map>
- <key>ButtonHPad</key>
- <map>
- <key>Comment</key>
- <string>Default horizontal spacing between buttons (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>ButtonHeight</key>
- <map>
- <key>Comment</key>
- <string>Default height for normal buttons (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>23</integer>
- </map>
- <key>ButtonHeightSmall</key>
- <map>
- <key>Comment</key>
- <string>Default height for small buttons (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>23</integer>
- </map>
- <key>CacheLocation</key>
- <map>
- <key>Comment</key>
- <string>Controls the location of the local disk cache</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>CacheLocationTopFolder</key>
- <map>
- <key>Comment</key>
- <string>Controls the top folder location of the the local disk cache</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>CacheNumberOfRegionsForObjects</key>
- <map>
- <key>Comment</key>
- <string>Controls number of regions to be cached for objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>128</integer>
- </map>
- <key>CacheSize</key>
- <map>
- <key>Comment</key>
- <string>Controls amount of hard drive space reserved for local file caching in MB</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>512</integer>
- </map>
- <key>CacheValidateCounter</key>
- <map>
- <key>Comment</key>
- <string>Used to distribute cache validation</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CameraMouseWheelZoom</key>
- <map>
- <key>Comment</key>
- <string>Camera zooms in and out with mousewheel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>CameraAngle</key>
- <map>
- <key>Comment</key>
- <string>Camera field of view angle (Radians)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.047197551</real>
- </map>
- <key>CameraOffset</key>
- <map>
- <key>Comment</key>
- <string>Render with camera offset from view frustum (rendering debug)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CameraOffsetBuild</key>
- <map>
- <key>Comment</key>
- <string>Default camera position relative to focus point when entering build mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>-6.0</real>
- <real>0.0</real>
- <real>6.0</real>
- </array>
- </map>
- <key>CameraOffsetRearView</key>
- <map>
- <key>Comment</key>
- <string>Initial camera offset from avatar in Rear View</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>-3.0</real>
- <real>0.0</real>
- <real>0.75</real>
- </array>
- </map>
- <key>CameraOffsetFrontView</key>
- <map>
- <key>Comment</key>
- <string>Initial camera offset from avatar in Front View</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>2.2</real>
- <real>0.0</real>
- <real>0.0</real>
- </array>
- </map>
- <key>CameraOffsetGroupView</key>
- <map>
- <key>Comment</key>
- <string>Initial camera offset from avatar in Group View</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>-1.0</real>
- <real>0.7</real>
- <real>0.5</real>
- </array>
- </map>
- <key>CameraOffsetScale</key>
- <map>
- <key>Comment</key>
- <string>Scales the default offset</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>CameraPosOnLogout</key>
- <map>
- <key>Comment</key>
- <string>Camera position when last logged out (global coordinates)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3D</string>
- <key>Value</key>
- <array>
- <real>0.0</real>
- <real>0.0</real>
- <real>0.0</real>
- </array>
- </map>
- <key>CameraPositionSmoothing</key>
- <map>
- <key>Comment</key>
- <string>Smooths camera position over time</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>CameraPreset</key>
- <map>
- <key>Comment</key>
- <string>Preset camera position - view (0 - rear, 1 - front, 2 - group)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>CameraFocusTransitionTime</key>
- <map>
- <key>Comment</key>
- <string>How many seconds it takes the camera to transition between focal distances</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
-
- <key>CameraFNumber</key>
- <map>
- <key>Comment</key>
- <string>Camera f-number value for DoF effect</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>9.0</real>
- </map>
-
- <key>CameraFocalLength</key>
- <map>
- <key>Comment</key>
- <string>Camera focal length for DoF effect (in millimeters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>50</real>
- </map>
-
- <key>CameraFieldOfView</key>
- <map>
- <key>Comment</key>
- <string>Vertical camera field of view for DoF effect (in degrees)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>60.0</real>
- </map>
-
- <key>CameraAspectRatio</key>
- <map>
- <key>Comment</key>
- <string>Camera aspect ratio for DoF effect</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.5</real>
- </map>
-
- <key>CertStore</key>
- <map>
- <key>Comment</key>
- <string>Specifies the Certificate Store for certificate trust verification</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>default</string>
- </map>
- <key>ChatBarStealsFocus</key>
- <map>
- <key>Comment</key>
- <string>Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LetterKeysFocusChatBar</key>
- <map>
- <key>Comment</key>
- <string>When printable characters keys (possibly with Shift held) are pressed, the chatbar takes focus</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ChatBubbleOpacity</key>
- <map>
- <key>Comment</key>
- <string>Opacity of chat bubble background (0.0 = completely transparent, 1.0 = completely opaque)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>ChatFontSize</key>
- <map>
- <key>Comment</key>
- <string>Size of chat text in chat console (0 = small, 1 = big)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatFullWidth</key>
- <map>
- <key>Comment</key>
- <string>Chat console takes up full width of SL window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatHistoryTornOff</key>
- <map>
- <key>Comment</key>
- <string>Show chat history window separately from Communicate window.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ChatOnlineNotification</key>
- <map>
- <key>Comment</key>
- <string>Provide notifications for when friend log on and off of SL</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatPersistTime</key>
- <map>
- <key>Comment</key>
- <string>Time for which chat stays visible in console (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>20.0</real>
- </map>
- <key>ChatShowTimestamps</key>
- <map>
- <key>Comment</key>
- <string>Show timestamps in chat</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatVisible</key>
- <map>
- <key>Comment</key>
- <string>Chat bar is visible</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatWindow</key>
- <map>
- <key>Comment</key>
- <string>Show chat in multiple windows(by default) or in one multi-tabbed window(requires restart)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CheesyBeacon</key>
- <map>
- <key>Comment</key>
- <string>Enable cheesy beacon effects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ClientSettingsFile</key>
- <map>
- <key>Comment</key>
- <string>Client settings file name (per install).</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>CloseChatOnReturn</key>
- <map>
- <key>Comment</key>
- <string>Close chat after hitting return</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CloseSnapshotOnKeep</key>
- <map>
- <key>Comment</key>
- <string>Close snapshot window after saving snapshot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>CmdLineDisableVoice</key>
- <map>
- <key>Comment</key>
- <string>Disable Voice.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CmdLineGridChoice</key>
- <map>
- <key>Comment</key>
- <string>The user's grid choice or ip address.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>CmdLineHelperURI</key>
- <map>
- <key>Comment</key>
- <string>Command line specified helper web CGI prefix to use.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>CmdLineLoginURI</key>
- <map>
- <key>Comment</key>
- <string>Command line specified login server and CGI prefix to use.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>LLSD</string>
- <key>Value</key>
- <array>
- <string />
- </array>
- </map>
- <key>CompressSnapshotsToDisk</key>
- <map>
- <key>Comment</key>
- <string>Compress snapshots saved to disk (Using JPEG 2000)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ConnectAsGod</key>
- <map>
- <key>Comment</key>
- <string>Log in a god if you have god access.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ConnectionPort</key>
- <map>
- <key>Comment</key>
- <string>Custom connection port number</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>13000</integer>
- </map>
- <key>ConnectionPortEnabled</key>
- <map>
- <key>Comment</key>
- <string>Use the custom connection port?</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ConsoleBackgroundOpacity</key>
- <map>
- <key>Comment</key>
- <string>Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.700</real>
- </map>
- <key>ConsoleBufferSize</key>
- <map>
- <key>Comment</key>
- <string>Size of chat console history (lines of chat)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>40</integer>
- </map>
- <key>ConsoleMaxLines</key>
- <map>
- <key>Comment</key>
- <string>Max number of lines of chat text visible in console.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>40</integer>
- </map>
- <key>ContactsTornOff</key>
- <map>
- <key>Comment</key>
- <string>Show contacts window separately from Communicate window.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CookiesEnabled</key>
- <map>
- <key>Comment</key>
- <string>Accept cookies from Web sites?</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BrowserJavascriptEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable Javascript in the built-in Web browser?</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>BrowserPluginsEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable Web plugins in the built-in Web browser?</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ChatBarCustomWidth</key>
- <map>
- <key>Comment</key>
- <string>Stores customized width of chat bar.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CreateToolCopyCenters</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>CreateToolCopyRotates</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CreateToolCopySelection</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>CreateToolKeepSelected</key>
- <map>
- <key>Comment</key>
- <string>After using create tool, keep the create tool active</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>Cursor3D</key>
- <map>
- <key>Comment</key>
- <string>Treat Joystick values as absolute positions (not deltas).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>CurrentGrid</key>
- <map>
- <key>Comment</key>
- <string>Currently Selected Grid</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>CustomServer</key>
- <map>
- <key>Comment</key>
- <string>Specifies IP address or hostname of grid to which you connect</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>DebugAvatarRezTime</key>
- <map>
- <key>Comment</key>
- <string>Display times for avatars to resolve.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugAvatarLocalTexLoadedTime</key>
- <map>
- <key>Comment</key>
- <string>Display time for loading avatar local textures.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugBeaconLineWidth</key>
- <map>
- <key>Comment</key>
- <string>Size of lines for Debug Beacons</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DebugInventoryFilters</key>
- <map>
- <key>Comment</key>
- <string>Turn on debugging display for inventory filtering</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugPermissions</key>
- <map>
- <key>Comment</key>
- <string>Log permissions for selected inventory items</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugPluginDisableTimeout</key>
- <map>
- <key>Comment</key>
- <string>Disable the code which watches for plugins that are crashed or hung</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowColor</key>
- <map>
- <key>Comment</key>
- <string>Show color under cursor</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowMemory</key>
- <map>
- <key>Comment</key>
- <string>Show Total Allocated Memory</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowRenderInfo</key>
- <map>
- <key>Comment</key>
- <string>Show stats about current scene</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowUploadCost</key>
- <map>
- <key>Comment</key>
- <string>Show what it would cost to upload assets in current scene</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowRenderMatrices</key>
- <map>
- <key>Comment</key>
- <string>Display values of current view and projection matrices.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowTextureInfo</key>
- <map>
- <key>Comment</key>
- <string>Show inertested texture info</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowTime</key>
- <map>
- <key>Comment</key>
- <string>Show time info</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugShowXUINames</key>
- <map>
- <key>Comment</key>
- <string>Show tooltips with XUI path to widget</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugStatModeFPS</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeBandwidth</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModePacketLoss</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatMode</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeKTrisDrawnFr</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeKTrisDrawnSec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeTotalObjs</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeNewObjs</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeTextureCount</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeRawCount</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeGLMem</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeFormattedMem</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeRawMem</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeBoundMem</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModePacketsIn</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModePacketsOut</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeObjects</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeTexture</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeAsset</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeLayers</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeActualIn</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeActualOut</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeVFSPendingOps</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeTimeDialation</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimFPS</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModePhysicsFPS</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModePinnedObjects</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeLowLODObjects</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeMemoryAllocated</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeAgentUpdatesSec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeMainAgents</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeChildAgents</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimObjects</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimActiveObjects</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimActiveScripts</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimScriptEvents</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimInPPS</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimOutPPS</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimPendingDownloads</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>SimPendingUploads</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimTotalUnackedBytes</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimFrameMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimNetMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSimPhysicsMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSimOtherMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimAgentMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimImagesMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimScriptMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSpareMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSimPhysicsStepMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSimPhysicsShapeUpdateMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSimPhysicsOtherMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimSleepMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugStatModeSimPumpIOMsec</key>
- <map>
- <key>Comment</key>
- <string>Mode of stat in Statistics floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>DebugViews</key>
- <map>
- <key>Comment</key>
- <string>Display debugging info for views.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DebugWindowProc</key>
- <map>
- <key>Comment</key>
- <string>Log windows messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DefaultFemaleAvatar</key>
- <map>
- <key>Comment</key>
- <string>Default Female Avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Female Shape &amp; Outfit</string>
- </map>
- <key>DefaultMaleAvatar</key>
- <map>
- <key>Comment</key>
- <string>Default Male Avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Male Shape &amp; Outfit</string>
- </map>
-
- <key>DefaultObjectTexture</key>
- <map>
- <key>Comment</key>
- <string>Texture used as 'Default' in texture picker. (UUID texture reference)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>89556747-24cb-43ed-920b-47caed15465f</string>
- </map>
- <key>DefaultUploadCost</key>
- <map>
- <key>Comment</key>
- <string>Default sound/image/file upload cost(in case economy data is not available).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>DestinationGuideURL</key>
- <map>
- <key>Comment</key>
- <string>Destination guide contents</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>DisableCameraConstraints</key>
- <map>
- <key>Comment</key>
- <string>Disable the normal bounds put on the camera by avatar position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisableMouseWarp</key>
- <map>
- <key>Comment</key>
- <string>Disable warping of the mouse to the center of the screen during alt-zoom and mouse look. Useful with certain input devices, mouse sharing programs like Synergy, or running under Parallels.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisableExternalBrowser</key>
- <map>
- <key>Comment</key>
- <string>Disable opening an external browser.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisableRendering</key>
- <map>
- <key>Comment</key>
- <string>Disable GL rendering and GUI (load testing)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisableTextHyperlinkActions</key>
- <map>
- <key>Comment</key>
- <string>Disable highlighting and linking of URLs in XUI text boxes</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisableVerticalSync</key>
- <map>
- <key>Comment</key>
- <string>Update frames as fast as possible (FALSE = update frames between display scans)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableGroupChatPopups</key>
- <map>
- <key>Comment</key>
- <string>Enable Incoming Group Chat Popups</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableIMChatPopups</key>
- <map>
- <key>Comment</key>
- <string>Enable Incoming IM Chat Popups</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayAvatarAgentTarget</key>
- <map>
- <key>Comment</key>
- <string>Show avatar positioning locators (animation debug)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DisplayChat</key>
- <map>
- <key>Comment</key>
- <string>Display Latest Chat message on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayDebug</key>
- <map>
- <key>Comment</key>
- <string>Display Network Information on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayDebugConsole</key>
- <map>
- <key>Comment</key>
- <string>Display Console Debug Information on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayIM</key>
- <map>
- <key>Comment</key>
- <string>Display Latest IM message on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayLinden</key>
- <map>
- <key>Comment</key>
- <string>Display Account Information on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayRegion</key>
- <map>
- <key>Comment</key>
- <string>Display Location information on LCD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DisplayTimecode</key>
- <map>
- <key>Comment</key>
- <string>Display timecode on screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>Disregard128DefaultDrawDistance</key>
- <map>
- <key>Comment</key>
- <string>Whether to use the auto default to 128 draw distance</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>Disregard96DefaultDrawDistance</key>
- <map>
- <key>Comment</key>
- <string>Whether to use the auto default to 96 draw distance</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ClickActionBuyEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable click to buy actions in tool pie menu</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ClickActionPayEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable click to pay actions in tool pie menu</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DoubleClickAutoPilot</key>
- <map>
- <key>Comment</key>
- <string>Enable double-click auto pilot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DoubleClickTeleport</key>
- <map>
- <key>Comment</key>
- <string>Enable double-click to teleport where allowed</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DoubleClickShowWorldMap</key>
- <map>
- <key>Comment</key>
- <string>Enable double-click to show world map from mini map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>DragAndDropToolTipDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before displaying tooltip when performing drag and drop operation</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.10000000149</real>
- </map>
- <key>DragAndDropDistanceThreshold</key>
- <map>
- <key>Comment</key>
- <string>Number of pixels that mouse should move before triggering drag and drop mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>DropShadowButton</key>
- <map>
- <key>Comment</key>
- <string>Drop shadow width for buttons (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>DropShadowFloater</key>
- <map>
- <key>Comment</key>
- <string>Drop shadow width for floaters (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>DropShadowSlider</key>
- <map>
- <key>Comment</key>
- <string>Drop shadow width for sliders (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>DropShadowTooltip</key>
- <map>
- <key>Comment</key>
- <string>Drop shadow width for tooltips (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>DumpVFSCaches</key>
- <map>
- <key>Comment</key>
- <string>Dump VFS caches on startup.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>DynamicCameraStrength</key>
- <map>
- <key>Comment</key>
- <string>Amount camera lags behind avatar motion (0 = none, 30 = avatar velocity)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>2.0</real>
- </map>
- <key>EditCameraMovement</key>
- <map>
- <key>Comment</key>
- <string>When entering build mode, camera moves up above avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>EditLinkedParts</key>
- <map>
- <key>Comment</key>
- <string>Select individual parts of linked objects</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>EffectScriptChatParticles</key>
- <map>
- <key>Comment</key>
- <string>1 = normal behavior, 0 = disable display of swirling lights when scripts communicate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableGrab</key>
- <map>
- <key>Comment</key>
- <string>Use Ctrl+mouse to grab and manipulate objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableAltZoom</key>
- <map>
- <key>Comment</key>
- <string>Use Alt+mouse to look at and zoom in on objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableMouselook</key>
- <map>
- <key>Comment</key>
- <string>Allow first person perspective and mouse control of camera</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableRippleWater</key>
- <map>
- <key>Comment</key>
- <string>Whether to use ripple water shader or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableTextureAtlas</key>
- <map>
- <key>Comment</key>
- <string>Whether to use texture atlas or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>EnableUIHints</key>
- <map>
- <key>Comment</key>
- <string>Toggles UI hint popups</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableVoiceChat</key>
- <map>
- <key>Comment</key>
- <string>Enable talking to other residents with a microphone</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnergyFromTop</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>20</integer>
- </map>
- <key>EnergyHeight</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>40</integer>
- </map>
- <key>EnergyWidth</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>175</integer>
- </map>
- <key>EventURL</key>
- <map>
- <key>Comment</key>
- <string>URL for Event website, displayed in the event floater</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://events.secondlife.com/viewer/embed/event/</string>
- </map>
- <key>EveryoneCopy</key>
- <map>
- <key>Comment</key>
- <string>Everyone can copy the newly created objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FeatureManagerHTTPTable</key>
- <map>
- <key>Comment</key>
- <string>Base directory for HTTP feature/gpu table fetches</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://viewer-settings.secondlife.com</string>
- </map>
- <key>FPSLogFrequency</key>
- <map>
- <key>Comment</key>
- <string>Seconds between display of FPS in log (0 for never)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>FilterItemsPerFrame</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>500</integer>
- </map>
- <key>FindLandArea</key>
- <map>
- <key>Comment</key>
- <string>Enables filtering of land search results by area</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FindLandPrice</key>
- <map>
- <key>Comment</key>
- <string>Enables filtering of land search results by price</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FindLandType</key>
- <map>
- <key>Comment</key>
- <string>Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale")</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>All</string>
- </map>
- <key>FindPeopleOnline</key>
- <map>
- <key>Comment</key>
- <string>Limits people search to only users who are logged on</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FindPlacesPictures</key>
- <map>
- <key>Comment</key>
- <string>Display only results of find places that have pictures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FirstLoginThisInstall</key>
- <map>
- <key>Comment</key>
- <string>Specifies that you have not successfully logged in since you installed the latest update</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FirstName</key>
- <map>
- <key>Comment</key>
- <string>Login first name</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>FirstPersonAvatarVisible</key>
- <map>
- <key>Comment</key>
- <string>Display avatar and attachments below neck while in mouselook</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FirstRunThisInstall</key>
- <map>
- <key>Comment</key>
- <string>Specifies that you have not run the viewer since you performed a clean install</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FirstLoginThisInstall</key>
- <map>
- <key>Comment</key>
- <string>Specifies that you have not logged in with the viewer since you performed a clean install</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FirstSelectedDisabledPopups</key>
- <map>
- <key>Comment</key>
- <string>Return false if there is not disabled popup selected in the list of floater preferences popups</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FirstSelectedEnabledPopups</key>
- <map>
- <key>Comment</key>
- <string>Return false if there is not enable popup selected in the list of floater preferences popups</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FixedWeather</key>
- <map>
- <key>Comment</key>
- <string>Weather effects do not change over time</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FloaterActiveSpeakersSortAscending</key>
- <map>
- <key>Comment</key>
- <string>Whether to sort up or down</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FloaterActiveSpeakersSortColumn</key>
- <map>
- <key>Comment</key>
- <string>Column name to sort on</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>speaking_status</string>
- </map>
- <key>FloaterMapNorth</key>
- <map>
- <key>Comment</key>
- <string>Floater Map North Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>N</string>
- </map>
- <key>FloaterMapNorthEast</key>
- <map>
- <key>Comment</key>
- <string>Floater Map North-East Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>NE</string>
- </map>
- <key>FloaterMapNorthWest</key>
- <map>
- <key>Comment</key>
- <string>Floater Map North-West Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>NW</string>
- </map>
- <key>FloaterMapEast</key>
- <map>
- <key>Comment</key>
- <string>Floater Map East Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>E</string>
- </map>
- <key>FloaterMapWest</key>
- <map>
- <key>Comment</key>
- <string>Floater Map West Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>W</string>
- </map>
- <key>FloaterMapSouth</key>
- <map>
- <key>Comment</key>
- <string>Floater Map South Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>S</string>
- </map>
- <key>FloaterMapSouthEast</key>
- <map>
- <key>Comment</key>
- <string>Floater Map South-East Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>SE</string>
- </map>
- <key>FloaterMapSouthWest</key>
- <map>
- <key>Comment</key>
- <string>Floater Map South-West Label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>SW</string>
- </map>
-
- <key>FloaterStatisticsRect</key>
- <map>
- <key>Comment</key>
- <string>Rectangle for chat history</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Rect</string>
- <key>Value</key>
- <array>
- <integer>0</integer>
- <integer>400</integer>
- <integer>250</integer>
- <integer>0</integer>
- </array>
- </map>
- <key>FlycamAbsolute</key>
- <map>
- <key>Comment</key>
- <string>Treat Flycam values as absolute positions (not deltas).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FlycamAxisDeadZone0</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 0 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone1</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 1 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone2</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 2 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone3</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 3 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone4</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 4 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone5</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 5 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisDeadZone6</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 6 dead zone.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>FlycamAxisScale0</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 0 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale1</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 1 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale2</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 2 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale3</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 3 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale4</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 4 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale5</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 5 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamAxisScale6</key>
- <map>
- <key>Comment</key>
- <string>Flycam axis 6 scaler.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamBuildModeScale</key>
- <map>
- <key>Comment</key>
- <string>Scale factor to apply to flycam movements when in build mode.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>FlycamFeathering</key>
- <map>
- <key>Comment</key>
- <string>Flycam feathering (less is softer)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>16.0</real>
- </map>
- <key>FlycamZoomDirect</key>
- <map>
- <key>Comment</key>
- <string>Map flycam zoom axis directly to camera zoom.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FlyingAtExit</key>
- <map>
- <key>Comment</key>
- <string>Was flying when last logged out, so fly when logging in</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FocusOffsetRearView</key>
- <map>
- <key>Comment</key>
- <string>Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3D</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.0</real>
- <real>1.0</real>
- </array>
- </map>
- <key>FocusOffsetFrontView</key>
- <map>
- <key>Comment</key>
- <string>Initial focus point offset relative to avatar for the camera preset Front View</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3D</string>
- <key>Value</key>
- <array>
- <real>0.0</real>
- <real>0.0</real>
- <real>0.0</real>
- </array>
- </map>
- <key>FocusOffsetGroupView</key>
- <map>
- <key>Comment</key>
- <string>Initial focus point offset relative to avatar for the camera preset Group View</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3D</string>
- <key>Value</key>
- <array>
- <real>1.5</real>
- <real>0.7</real>
- <real>1.0</real>
- </array>
- </map>
- <key>FocusPosOnLogout</key>
- <map>
- <key>Comment</key>
- <string>Camera focus point when last logged out (global coordinates)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3D</string>
- <key>Value</key>
- <array>
- <real>0.0</real>
- <real>0.0</real>
- <real>0.0</real>
- </array>
- </map>
- <key>FolderAutoOpenDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before automatically expanding the folder under the mouse when performing inventory drag and drop</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.75</real>
- </map>
- <key>FolderLoadingMessageWaitTime</key>
- <map>
- <key>Comment</key>
- <string>Seconds to wait before showing the LOADING... text in folder views</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>FontScreenDPI</key>
- <map>
- <key>Comment</key>
- <string>Font resolution, higher is bigger (pixels per inch)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>96.0</real>
- </map>
- <key>ForceAssetFail</key>
- <map>
- <key>Comment</key>
- <string>Force wearable fetches to fail for this asset type.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>255</integer>
- </map>
- <key>ForceShowGrid</key>
- <map>
- <key>Comment</key>
- <string>Always show grid dropdown on login screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ForceMandatoryUpdate</key>
- <map>
- <key>Comment</key>
- <string>For QA: On next startup, forces the auto-updater to run</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FreezeTime</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>FullScreenAspectRatio</key>
- <map>
- <key>Comment</key>
- <string>Aspect ratio of fullscreen display (width / height)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3</real>
- </map>
- <key>FullScreenAutoDetectAspectRatio</key>
- <map>
- <key>Comment</key>
- <string>Automatically detect proper aspect ratio for fullscreen display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>GesturesMarketplaceURL</key>
- <map>
- <key>Comment</key>
- <string>URL to the Gestures Marketplace</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://www.xstreetsl.com/modules.php?name=Marketplace&amp;CategoryID=233</string>
- </map>
- <key>GridCrossSections</key>
- <map>
- <key>Comment</key>
- <string>Highlight cross sections of prims with grid manipulation plane.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>GridDrawSize</key>
- <map>
- <key>Comment</key>
- <string>Visible extent of 2D snap grid (meters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>12.0</real>
- </map>
- <key>GridMode</key>
- <map>
- <key>Comment</key>
- <string>Snap grid reference frame (0 = world, 1 = local, 2 = reference object)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>GridOpacity</key>
- <map>
- <key>Comment</key>
- <string>Grid line opacity (0.0 = completely transparent, 1.0 = completely opaque)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.699999988079</real>
- </map>
- <key>GridResolution</key>
- <map>
- <key>Comment</key>
- <string>Size of single grid step (meters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>GridSubUnit</key>
- <map>
- <key>Comment</key>
- <string>Display fractional grid steps, relative to grid size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>GridSubdivision</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of times to divide single snap grid unit when GridSubUnit is true</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>32</integer>
- </map>
- <key>GroupNotifyBoxHeight</key>
- <map>
- <key>Comment</key>
- <string>Height of group notice messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>260</integer>
- </map>
- <key>GroupNotifyBoxWidth</key>
- <map>
- <key>Comment</key>
- <string>Width of group notice messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>305</integer>
- </map>
- <key>HelpUseLocal</key>
- <map>
- <key>Comment</key>
- <string>If set, always use this for help: skins/default/html/[LANGUAGE]/help-offline/index.html</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>HelpURLFormat</key>
- <map>
- <key>Comment</key>
- <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://viewer-help.secondlife.com/[LANGUAGE]/[CHANNEL]/[VERSION]/[TOPIC][DEBUG_MODE]</string>
- </map>
- <key>HomeSidePanelURL</key>
- <map>
- <key>Comment</key>
- <string>URL for the web page to display in the Home side panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://viewer-sidebar.secondlife.com/sidebar.html?p=[AUTH_TOKEN]&amp;lang=[LANGUAGE]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]&amp;firstlogin=[FIRST_LOGIN]</string>
- </map>
- <key>SearchURL</key>
- <map>
- <key>Comment</key>
- <string>URL for Search website, displayed in the Find floater</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&amp;p=[AUTH_TOKEN]&amp;r=[MATURITY]&amp;lang=[LANGUAGE]&amp;g=[GODLIKE]&amp;sid=[SESSION_ID]&amp;rid=[REGION_ID]&amp;pid=[PARCEL_ID]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]</string>
- </map>
- <key>WebProfileURL</key>
- <map>
- <key>Comment</key>
- <string>URL for Web Profiles</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://my.secondlife.com/[AGENT_NAME]</string>
- </map>
- <key>WebProfileNonProductionURL</key>
- <map>
- <key>Comment</key>
- <string>URL for Web Profiles on Non-Production grids</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://my-demo.secondlife.com/[AGENT_NAME]</string>
- </map>
- <key>HighResSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Double resolution of snapshot from current window resolution</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>HideSelectedObjects</key>
- <map>
- <key>Comment</key>
- <string>Hide Selected Objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>HostID</key>
- <map>
- <key>Comment</key>
- <string>Machine identifier for hosted Second Life instances</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>HtmlHelpLastPage</key>
- <map>
- <key>Comment</key>
- <string>Last URL visited via help system</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>IMShowTimestamps</key>
- <map>
- <key>Comment</key>
- <string>Show timestamps in IM</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>IMShowControlPanel</key>
- <map>
- <key>Comment</key>
- <string>Show IM Control Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>IgnoreAllNotifications</key>
- <map>
- <key>Comment</key>
- <string>Ignore all notifications so we never need user input on them.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>IgnorePixelDepth</key>
- <map>
- <key>Comment</key>
- <string>Ignore pixel depth settings.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ImagePipelineUseHTTP</key>
- <map>
- <key>Comment</key>
- <string>If TRUE use HTTP GET to fetch textures from the server</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>InactiveFloaterTransparency</key>
- <map>
- <key>Comment</key>
- <string>Transparency of inactive floaters (floaters that have no focus)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.65</real>
- </map>
- <key>InBandwidth</key>
- <map>
- <key>Comment</key>
- <string>Incoming bandwidth throttle (bps)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>InspectorFadeTime</key>
- <map>
- <key>Comment</key>
- <string>Fade out timing for inspectors</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>InspectorShowTime</key>
- <map>
- <key>Comment</key>
- <string>Stay timing for inspectors</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3.0</real>
- </map>
- <key>InstallLanguage</key>
- <map>
- <key>Comment</key>
- <string>Language passed from installer (for UI)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>default</string>
- </map>
- <key>InventoryAutoOpenDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before automatically opening inventory when mouse is over inventory button when performing inventory drag and drop</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>InventoryLinking</key>
- <map>
- <key>Comment</key>
- <string>Enable ability to create links to folders and items via "Paste as link".</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>InventorySortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>7</integer>
- </map>
- <key>InvertMouse</key>
- <map>
- <key>Comment</key>
- <string>When in mouselook, moving mouse up looks down and vice verse (FALSE = moving up looks up)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>JoystickAvatarEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enables the Joystick to control Avatar movement.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>JoystickAxis0</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 0 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>JoystickAxis1</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 1 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>JoystickAxis2</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 2 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>JoystickAxis3</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 3 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>JoystickAxis4</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 4 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>JoystickAxis5</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 5 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>JoystickAxis6</key>
- <map>
- <key>Comment</key>
- <string>Flycam hardware axis mapping for internal axis 6 ([0, 5]).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>JoystickBuildEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enables the Joystick to move edited objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>JoystickEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enables Joystick Input.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>JoystickFlycamEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enables the Joystick to control the flycam.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>JoystickInitialized</key>
- <map>
- <key>Comment</key>
- <string>Whether or not a joystick has been detected and initiailized.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>JoystickMouselookYaw</key>
- <map>
- <key>Comment</key>
- <string>Pass joystick yaw to scripts in Mouselook.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>JoystickRunThreshold</key>
- <map>
- <key>Comment</key>
- <string>Input threshold to initiate running</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>KeepAspectForSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Use full window when taking snapshot, regardless of requested image size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LandBrushSize</key>
- <map>
- <key>Comment</key>
- <string>Size of affected region when using teraform tool</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>2.0</real>
- </map>
- <key>LCDDestination</key>
- <map>
- <key>Comment</key>
- <string>Which LCD to use</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LSLFindCaseInsensitivity</key>
- <map>
- <key>Comment</key>
- <string>Use case insensitivity when searching in LSL editor</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LSLHelpURL</key>
- <map>
- <key>Comment</key>
- <string>URL that points to LSL help files, with [LSL_STRING] corresponding to the referenced LSL function or keyword</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://wiki.secondlife.com/wiki/[LSL_STRING]</string>
- </map>
- <key>LagMeterShrunk</key>
- <map>
- <key>Comment</key>
- <string>Last large/small state for lag meter</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>Language</key>
- <map>
- <key>Comment</key>
- <string>Language specifier (for UI)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>default</string>
- </map>
- <key>LanguageIsPublic</key>
- <map>
- <key>Comment</key>
- <string>Let other residents see our language information</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LastGPUClass</key>
- <map>
- <key>Comment</key>
- <string>[DO NOT MODIFY] previous GPU class for tracking hardware changes</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>LastFeatureVersion</key>
- <map>
- <key>Comment</key>
- <string>[DO NOT MODIFY] Version number for tracking hardware changes</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LastFindPanel</key>
- <map>
- <key>Comment</key>
- <string>Controls which find operation appears by default when clicking "Find" button </string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>find_all_panel</string>
- </map>
- <key>LastName</key>
- <map>
- <key>Comment</key>
- <string>Login last name</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>LastPrefTab</key>
- <map>
- <key>Comment</key>
- <string>Last selected tab in preferences window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LastMediaSettingsTab</key>
- <map>
- <key>Comment</key>
- <string>Last selected tab in media settings window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LastRunVersion</key>
- <map>
- <key>Comment</key>
- <string>Version number of last instance of the viewer that you ran</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0.0.0</string>
- </map>
-
- <key>LastSnapshotToEmailHeight</key>
- <map>
- <key>Comment</key>
- <string>The height of the last email snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>768</integer>
- </map>
- <key>LastSnapshotToEmailWidth</key>
- <map>
- <key>Comment</key>
- <string>The width of the last email snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1024</integer>
- </map>
- <key>LastSnapshotToDiskHeight</key>
- <map>
- <key>Comment</key>
- <string>The height of the last disk snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>768</integer>
- </map>
- <key>LastSnapshotToDiskWidth</key>
- <map>
- <key>Comment</key>
- <string>The width of the last disk snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1024</integer>
- </map>
- <key>LastSnapshotToInventoryHeight</key>
- <map>
- <key>Comment</key>
- <string>The height of the last texture snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>512</integer>
- </map>
- <key>LastSnapshotToInventoryWidth</key>
- <map>
- <key>Comment</key>
- <string>The width of the last texture snapshot, in px</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>512</integer>
- </map>
- <key>LastSnapshotType</key>
- <map>
- <key>Comment</key>
- <string>Select this as next type of snapshot to take (0 = postcard, 1 = texture, 2 = local image)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LeftClickShowMenu</key>
- <map>
- <key>Comment</key>
- <string>Left click opens pie menu (FALSE = left click touches or grabs object)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LimitDragDistance</key>
- <map>
- <key>Comment</key>
- <string>Limit translation of object via translate tool</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LimitSelectDistance</key>
- <map>
- <key>Comment</key>
- <string>Disallow selection of objects beyond max select distance</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LipSyncAah</key>
- <map>
- <key>Comment</key>
- <string>Aah (jaw opening) babble loop</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>257998776531013446642343</string>
- </map>
- <key>LipSyncAahPowerTransfer</key>
- <map>
- <key>Comment</key>
- <string>Transfer curve for Voice Interface power to aah lip sync amplitude</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0000123456789</string>
- </map>
- <key>LipSyncEnabled</key>
- <map>
- <key>Comment</key>
- <string>0 disable lip-sync, 1 enable babble loop</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LipSyncOoh</key>
- <map>
- <key>Comment</key>
- <string>Ooh (mouth width) babble loop</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>1247898743223344444443200000</string>
- </map>
- <key>LipSyncOohAahRate</key>
- <map>
- <key>Comment</key>
- <string>Rate to babble Ooh and Aah (/sec)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>24.0</real>
- </map>
- <key>LipSyncOohPowerTransfer</key>
- <map>
- <key>Comment</key>
- <string>Transfer curve for Voice Interface power to ooh lip sync amplitude</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0012345566778899</string>
- </map>
- <key>LocalCacheVersion</key>
- <map>
- <key>Comment</key>
- <string>Version number of cache</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LocalFileSystemBrowsingEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable/disable access to the local file system via the file picker</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LoginSRVTimeout</key>
- <map>
- <key>Comment</key>
- <string>Duration in seconds of the login SRV request timeout</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>LoginSRVPump</key>
- <map>
- <key>Comment</key>
- <string>Name of the message pump that handles SRV request</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>LLAres</string>
- </map>
- <key>LogMessages</key>
- <map>
- <key>Comment</key>
- <string>Log network traffic</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LogTextureNetworkTraffic</key>
- <map>
- <key>Comment</key>
- <string>Log network traffic for textures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LoginAsGod</key>
- <map>
- <key>Comment</key>
- <string>Attempt to login with god powers (Linden accounts only)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LoginLocation</key>
- <map>
- <key>Comment</key>
- <string>Login location ('last', 'home')</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>last</string>
- </map>
- <key>LoginPage</key>
- <map>
- <key>Comment</key>
- <string>Login authentication page.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>LosslessJ2CUpload</key>
- <map>
- <key>Comment</key>
- <string>Use lossless compression for small image uploads</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MainloopTimeoutDefault</key>
- <map>
- <key>Comment</key>
- <string>Timeout duration for mainloop lock detection, in seconds.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>20.0</real>
- </map>
- <key>MapOverlayIndex</key>
- <map>
- <key>Comment</key>
- <string>Currently selected world map type</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MapScale</key>
- <map>
- <key>Comment</key>
- <string>World map zoom level (pixels per region)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>128.0</real>
- </map>
- <key>MapServerURL</key>
- <map>
- <key>Comment</key>
- <string>World map URL template for locating map tiles</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://map.secondlife.com.s3.amazonaws.com/</string>
- </map>
- <key>CurrentMapServerURL</key>
- <map>
- <key>Comment</key>
- <string>Current Session World map URL</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>MapShowEvents</key>
- <map>
- <key>Comment</key>
- <string>Show events on world map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MapShowInfohubs</key>
- <map>
- <key>Comment</key>
- <string>Show infohubs on the world map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MapShowLandForSale</key>
- <map>
- <key>Comment</key>
- <string>Show land for sale on world map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MapShowPeople</key>
- <map>
- <key>Comment</key>
- <string>Show other users on world map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MapShowTelehubs</key>
- <map>
- <key>Comment</key>
- <string>Show telehubs on world map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MiniMapAutoCenter</key>
- <map>
- <key>Comment</key>
- <string>Center the focal point of the minimap.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>Marker</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>MarketplaceURL</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/</string>
- </map>
- <key>MarketplaceURL_objectFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Attachments Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/attachments</string>
- </map>
- <key>MarketplaceURL_objectMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Attachments Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/attachments</string>
- </map>
- <key>MarketplaceURL_clothingFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Clothing Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/clothing_female_avatar</string>
- </map>
- <key>MarketplaceURL_clothingMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Clothing Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/clothing_male_avatar</string>
- </map>
- <key>MarketplaceURL_bodypartFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Bodyparts Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com</string>
- </map>
- <key>MarketplaceURL_bodypartMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Bodyparts Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/</string>
- </map>
- <key>MarketplaceURL_glovesMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Gloves Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/gloves_both_women_and_men</string>
- </map>
- <key>MarketplaceURL_glovesFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Gloves Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/gloves_both_women_and_men</string>
- </map>
- <key>MarketplaceURL_jacketFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Jacket Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/jacket_womens</string>
- </map>
- <key>MarketplaceURL_jacketMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Jacket Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/jacket_mens</string>
- </map>
- <key>MarketplaceURL_shirtFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shirt Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/shirt_womens</string>
- </map>
- <key>MarketplaceURL_shirtMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shirt Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/shirt_mens</string>
- </map>
- <key>MarketplaceURL_undershirtFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Undershirt Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/undershirt_womens</string>
- </map>
- <key>MarketplaceURL_undershirtMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Undershirt Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/undershirt_mens</string>
- </map>
- <key>MarketplaceURL_skirtFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Skirt Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/skirts_women</string>
- </map>
- <key>MarketplaceURL_skirtMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Skirt Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/skirts_women</string>
- </map>
- <key>MarketplaceURL_pantsFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Pants Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/pants_women</string>
- </map>
- <key>MarketplaceURL_pantsMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Pants Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/pants_men</string>
- </map>
- <key>MarketplaceURL_underpantsFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Underwear Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/underwear_women</string>
- </map>
- <key>MarketplaceURL_underpantsMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Underwear Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/underwear_men</string>
- </map>
- <key>MarketplaceURL_shoesFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shoes Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/shoes_women</string>
- </map>
- <key>MarketplaceURL_shoesMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shoes Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/shoes_men</string>
- </map>
- <key>MarketplaceURL_socksFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Socks Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/socks_women</string>
- </map>
- <key>MarketplaceURL_socksMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Socks Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/socks_women</string>
- </map>
- <key>MarketplaceURL_tattooMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Tattoo Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/tattoo_both_women_and_men</string>
- </map>
- <key>MarketplaceURL_tattooFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Tattoo Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/tattoo_both_women_and_men</string>
- </map>
- <key>MarketplaceURL_hairFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Hair Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_hair</string>
- </map>
- <key>MarketplaceURL_hairMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Hair Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_hair</string>
- </map>
- <key>MarketplaceURL_eyesFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Eyes Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_eyes</string>
- </map>
- <key>MarketplaceURL_eyesMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Eyes Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_eyes</string>
- </map>
- <key>MarketplaceURL_shapeFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shape Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_shape</string>
- </map>
- <key>MarketplaceURL_shapeMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Shape Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_shape</string>
- </map>
- <key>MarketplaceURL_skinFemale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Skin Female</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_skin</string>
- </map>
- <key>MarketplaceURL_skinMale</key>
- <map>
- <key>Comment</key>
- <string>URL to the Marketplace Skins Male</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_skin</string>
- </map>
- <key>MaxDragDistance</key>
- <map>
- <key>Comment</key>
- <string>Maximum allowed translation distance in a single operation of translate tool (meters from start point)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>48.0</real>
- </map>
- <key>MaxSelectDistance</key>
- <map>
- <key>Comment</key>
- <string>Maximum allowed selection distance (meters from avatar)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>64.0</real>
- </map>
- <key>MaxWearableWaitTime</key>
- <map>
- <key>Comment</key>
- <string>Max seconds to wait for wearable assets to fetch.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>60.0</real>
- </map>
- <key>MediaControlFadeTime</key>
- <map>
- <key>Comment</key>
- <string>Amount of time (in seconds) that the media control fades</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.5</real>
- </map>
- <key>MediaControlTimeout</key>
- <map>
- <key>Comment</key>
- <string>Amount of time (in seconds) for media controls to fade with no mouse activity</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3.0</real>
- </map>
- <key>MediaEnablePopups</key>
- <map>
- <key>Comment</key>
- <string>If true, enable targeted links and javascript in media to open new media browser windows without a prompt.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MediaOnAPrimUI</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to show the "link sharing" UI</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MediaPerformanceManagerDebug</key>
- <map>
- <key>Comment</key>
- <string>Whether to show debug data for the media performance manager in the nearby media list.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MediaShowOnOthers</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to show media on other avatars</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MediaShowOutsideParcel</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to show media from outside the current parcel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MediaShowWithinParcel</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to show media within the current parcel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MediaTentativeAutoPlay</key>
- <map>
- <key>Comment</key>
- <string>This is a tentative flag that may be temporarily set off by the user, until she teleports</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MemoryLogFrequency</key>
- <map>
- <key>Comment</key>
- <string>Seconds between display of Memory in log (0 for never)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>600.0</real>
- </map>
- <key>MemProfiling</key>
- <map>
- <key>Comment</key>
- <string>You want to use tcmalloc's memory profiling options.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MenuAccessKeyTime</key>
- <map>
- <key>Comment</key>
- <string>Time (seconds) in which the menu key must be tapped to move focus to the menu bar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>MenuBarHeight</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>18</integer>
- </map>
- <key>MenuBarWidth</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>410</integer>
- </map>
- <key>MePanelOpened</key>
- <map>
- <key>Comment</key>
- <string>Indicates that Me Panel was opened at least once after Viewer was installed</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <real>0</real>
- </map>
- <key>MeshEnabled</key>
- <map>
- <key>Comment</key>
- <string>Expose UI for mesh functionality (may require restart to take effect).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <real>1</real>
- </map>
- <key>MeshImportUseSLM</key>
- <map>
- <key>Comment</key>
- <string>Use cached copy of last upload for a dae if available instead of loading dae file from scratch.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <real>0</real>
- </map>
- <key>MigrateCacheDirectory</key>
- <map>
- <key>Comment</key>
- <string>Check for old version of disk cache to migrate to current location</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MiniMapPrimMaxRadius</key>
- <map>
- <key>Comment</key>
- <string>Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>256.0</real>
- </map>
- <key>MiniMapRotate</key>
- <map>
- <key>Comment</key>
- <string>Rotate miniature world map to avatar direction</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>MiniMapScale</key>
- <map>
- <key>Comment</key>
- <string>Miniature world map zoom level (pixels per region)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>128.0</real>
- </map>
- <key>MouseSensitivity</key>
- <map>
- <key>Comment</key>
- <string>Controls responsiveness of mouse when in mouselook mode (fraction or multiple of default mouse sensitivity)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3.0</real>
- </map>
- <key>MouseSmooth</key>
- <map>
- <key>Comment</key>
- <string>Smooths out motion of mouse when in mouselook mode.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MouseSun</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteAmbient</key>
- <map>
- <key>Comment</key>
- <string>Ambient sound effects, such as wind noise, play at 0 volume</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteAudio</key>
- <map>
- <key>Comment</key>
- <string>All audio plays at 0 volume (streaming audio still takes up bandwidth, for example)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteMedia</key>
- <map>
- <key>Comment</key>
- <string>Media plays at 0 volume (streaming audio still takes up bandwidth)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteMusic</key>
- <map>
- <key>Comment</key>
- <string>Music plays at 0 volume (streaming audio still takes up bandwidth)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteSounds</key>
- <map>
- <key>Comment</key>
- <string>Sound effects play at 0 volume</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteUI</key>
- <map>
- <key>Comment</key>
- <string>UI sound effects play at 0 volume</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteVoice</key>
- <map>
- <key>Comment</key>
- <string>Voice plays at 0 volume (streaming audio still takes up bandwidth)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MuteWhenMinimized</key>
- <map>
- <key>Comment</key>
- <string>Mute audio when SL window is minimized</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>MyOutfitsAutofill</key>
- <map>
- <key>Comment</key>
- <string>Always autofill My Outfits from library when empty (else happens just once).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NearMeRange</key>
- <map>
- <key>Comment</key>
- <string>Search radius for nearby avatars</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <integer>130</integer>
- </map>
- <key>NextOwnerCopy</key>
- <map>
- <key>Comment</key>
- <string>Newly created objects can be copied by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NextOwnerModify</key>
- <map>
- <key>Comment</key>
- <string>Newly created objects can be modified by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NextOwnerTransfer</key>
- <map>
- <key>Comment</key>
- <string>Newly created objects can be resold or given away by next owner</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>NewCacheLocation</key>
- <map>
- <key>Comment</key>
- <string>Change the location of the local disk cache to this</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>NewCacheLocationTopFolder</key>
- <map>
- <key>Comment</key>
- <string>Change the top folder location of the local disk cache to this</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>NextLoginLocation</key>
- <map>
- <key>Comment</key>
- <string>Location to log into by default.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>NoAudio</key>
- <map>
- <key>Comment</key>
- <string>Disable audio playback.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NoHardwareProbe</key>
- <map>
- <key>Comment</key>
- <string>Disable hardware probe.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NoInventoryLibrary</key>
- <map>
- <key>Comment</key>
- <string>Do not request inventory library.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NoPreload</key>
- <map>
- <key>Comment</key>
- <string>Disable sound and image preload.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NoVerifySSLCert</key>
- <map>
- <key>Comment</key>
- <string>Do not verify SSL peers.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NotifyBoxHeight</key>
- <map>
- <key>Comment</key>
- <string>Height of notification messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>200</integer>
- </map>
- <key>NotifyBoxWidth</key>
- <map>
- <key>Comment</key>
- <string>Width of notification messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>305</integer>
- </map>
- <key>NotificationToastLifeTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a notification toast exists</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>NotificationTipToastLifeTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a notification tip toast exist</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>ToastFadingTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a toast is fading </string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>NearbyToastFadingTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a nearby chat toast is fading </string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>NearbyToastLifeTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a nearby chat toast exists</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>23</integer>
- </map>
- <key>StartUpToastLifeTime</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds while a StartUp toast exist</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>ToastGap</key>
- <map>
- <key>Comment</key>
- <string>Gap between toasts on a screen (min. value is 5)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>7</integer>
- </map>
- <key>ToastButtonWidth</key>
- <map>
- <key>Comment</key>
- <string>Default width of buttons in the toast.
- Notes:
- If required width will be less then this one, a button will be reshaped to default size , otherwise to required
- Change of this parameter will affect the layout of buttons in notification toast.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>90</integer>
- </map>
- <key>ChannelBottomPanelMargin</key>
- <map>
- <key>Comment</key>
- <string>Space from a lower toast to the Bottom Tray</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>35</integer>
- </map>
- <key>NotificationChannelRightMargin</key>
- <map>
- <key>Comment</key>
- <string>Space between toasts and a right border of an area where they can appear</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>NotificationChannelHeightRatio</key>
- <map>
- <key>Comment</key>
- <string>Notification channel and World View ratio(0.0 - always show 1 notification, 1.0 - max ratio).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>OverflowToastHeight</key>
- <map>
- <key>Comment</key>
- <string>Height of an overflow toast</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>72</integer>
- </map>
- <key>NotifyMoneyChange</key>
- <map>
- <key>Comment</key>
- <string>Pop up notifications for all L$ transactions</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>NotifyTipDuration</key>
- <map>
- <key>Comment</key>
- <string>Length of time that notification tips stay on screen (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4.0</real>
- </map>
- <key>NumSessions</key>
- <map>
- <key>Comment</key>
- <string>Number of successful logins to Second Life</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NumpadControl</key>
- <map>
- <key>Comment</key>
- <string>How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ObjectCacheEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable the object cache.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OpenDebugStatAdvanced</key>
- <map>
- <key>Comment</key>
- <string>Expand advanced performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>OpenDebugStatBasic</key>
- <map>
- <key>Comment</key>
- <string>Expand basic performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OpenDebugStatNet</key>
- <map>
- <key>Comment</key>
- <string>Expand network stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OpenDebugStatRender</key>
- <map>
- <key>Comment</key>
- <string>Expand render stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OpenDebugStatSim</key>
- <map>
- <key>Comment</key>
- <string>Expand simulator performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OpenDebugStatTexture</key>
- <map>
- <key>Comment</key>
- <string>Expand Texture performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>OpenDebugStatPhysicsDetails</key>
- <map>
- <key>Comment</key>
- <string>Expand Physics Details performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>OpenDebugStatSimTime</key>
- <map>
- <key>Comment</key>
- <string>Expand Simulator Time performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>OpenDebugStatSimTimeDetails</key>
- <map>
- <key>Comment</key>
- <string>Expand Simulator Time Details performance stats display</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>OutBandwidth</key>
- <map>
- <key>Comment</key>
- <string>Outgoing bandwidth throttle (bps)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>OverlayTitle</key>
- <map>
- <key>Comment</key>
- <string>Controls watermark text message displayed on screen when "ShowOverlayTitle" is enabled (one word, underscores become spaces)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Set_via_OverlayTitle_in_settings.xml</string>
- </map>
- <key>PTTCurrentlyEnabled</key>
- <map>
- <key>Comment</key>
- <string>Use Push to Talk mode</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PacketDropPercentage</key>
- <map>
- <key>Comment</key>
- <string>Percentage of packets dropped by the client.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>ObjectCostHighThreshold</key>
- <map>
- <key>Comment</key>
- <string>Threshold at which object cost is considered high (displayed in red).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>50.0</real>
- </map>
- <key>ObjectCostLowColor</key>
- <map>
- <key>Comment</key>
- <string>Color for object with a low object cost.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>0.0</real>
- <real>0.5</real>
- <real>1.0</real>
- <real>0.5</real>
- </array>
- </map>
- <key>ObjectCostMidColor</key>
- <map>
- <key>Comment</key>
- <string>Color for object with a medium object cost.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.75</real>
- <real>0.0</real>
- <real>0.65</real>
- </array>
- </map>
- <key>ObjectCostHighColor</key>
- <map>
- <key>Comment</key>
- <string>Color for object a high object cost.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.0</real>
- <real>0.0</real>
- <real>0.75</real>
- </array>
- </map>
-
- <key>ParcelMediaAutoPlayEnable</key>
- <map>
- <key>Comment</key>
- <string>Auto play parcel media when available</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ParticipantListShowIcons</key>
- <map>
- <key>Comment</key>
- <string>Show/hide people icons in participant list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PerAccountSettingsFile</key>
- <map>
- <key>Comment</key>
- <string>Persisted client settings file name (per user).</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>PermissionsCautionEnabled</key>
- <map>
- <key>Comment</key>
- <string>When enabled, changes the handling of script permission requests to help avoid accidental granting of certain permissions, such as the debit permission</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PermissionsCautionNotifyBoxHeight</key>
- <map>
- <key>Comment</key>
- <string>Height of caution-style notification messages</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>344</integer>
- </map>
- <key>PickerContextOpacity</key>
- <map>
- <key>Comment</key>
- <string>Controls overall opacity of context frustrum connecting color and texture pickers with their swatches</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.34999999404</real>
- </map>
- <key>PicksPerSecondMouseMoving</key>
- <map>
- <key>Comment</key>
- <string>How often to perform hover picks while the mouse is moving (picks per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>PicksPerSecondMouseStationary</key>
- <map>
- <key>Comment</key>
- <string>How often to perform hover picks while the mouse is stationary (picks per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>PieMenuLineWidth</key>
- <map>
- <key>Comment</key>
- <string>Width of lines in pie menu display (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>2.5</real>
- </map>
- <key>PingInterpolate</key>
- <map>
- <key>Comment</key>
- <string>Extrapolate object position along velocity vector based on ping delay</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>PitchFromMousePosition</key>
- <map>
- <key>Comment</key>
- <string>Vertical range over which avatar head tracks mouse position (degrees of head rotation from top of window to bottom)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>90.0</real>
- </map>
- <key>PlayTypingAnim</key>
- <map>
- <key>Comment</key>
- <string>Your avatar plays the typing animation whenever you type in the chat bar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PluginAttachDebuggerToPlugins</key>
- <map>
- <key>Comment</key>
- <string>If true, attach a debugger session to each plugin process as it's launched.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>PluginInstancesCPULimit</key>
- <map>
- <key>Comment</key>
- <string>Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.9</real>
- </map>
-
- <key>PlainTextChatHistory</key>
- <map>
- <key>Comment</key>
- <string>Enable/Disable plain text chat history style</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>PluginInstancesLow</key>
- <map>
- <key>Comment</key>
- <string>Limit on the number of inworld media plugins that will run at "low" priority</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>PluginInstancesNormal</key>
- <map>
- <key>Comment</key>
- <string>Limit on the number of inworld media plugins that will run at "normal" or higher priority</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>PluginInstancesTotal</key>
- <map>
- <key>Comment</key>
- <string>Hard limit on the number of plugins that will be instantiated at once for inworld media</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>8</integer>
- </map>
-
- <key>PluginUseReadThread</key>
- <map>
- <key>Comment</key>
- <string>Use a separate thread to read incoming messages from plugins</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>PrecachingDelay</key>
- <map>
- <key>Comment</key>
- <string>Delay when logging in to load world before showing it (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>6.0</real>
- </map>
- <key>PreferredMaturity</key>
- <map>
- <key>Comment</key>
- <string>Setting for the user's preferred maturity level (consts in indra_constants.h)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>13</integer>
- </map>
-
- <key>PreviewAmbientColor</key>
- <map>
- <key>Comment</key>
- <string>Ambient color of preview render.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>0.0</real>
- <real>0.0</real>
- <real>0.0</real>
- <real>1.0</real>
- </array>
- </map>
-
-
- <key>PreviewDiffuse0</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 0.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewDiffuse1</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 1.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>0.25</real>
- <real>0.25</real>
- <real>0.25</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewDiffuse2</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 2.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewSpecular0</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 0.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewSpecular1</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 1.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewSpecular2</key>
- <map>
- <key>Comment</key>
- <string>Diffise color of preview light 2.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- <real>1.0</real>
- </array>
- </map>
-
-
- <key>PreviewDirection0</key>
- <map>
- <key>Comment</key>
- <string>Direction of light 0 for preview render.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>-0.75</real>
- <real>1</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>PreviewDirection1</key>
- <map>
- <key>Comment</key>
- <string>Direction of light 1 for preview render.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>0.5</real>
- <real>-0.6</real>
- <real>0.4</real>
- </array>
- </map>
-
- <key>PreviewDirection2</key>
- <map>
- <key>Comment</key>
- <string>Direction of light 2 for preview render.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>0.5</real>
- <real>-0.8</real>
- <real>0.3</real>
- </array>
- </map>
-
- <key>PrimMediaMasterEnabled</key>
- <map>
- <key>Comment</key>
- <string>Whether or not Media on a Prim is enabled.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PrimMediaControlsUseHoverControlSet</key>
- <map>
- <key>Comment</key>
- <string>Whether or not hovering over prim media uses minimal "hover" controls or the authored control set.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>PrimMediaDragNDrop</key>
- <map>
- <key>Comment</key>
- <string>Enable drag and drop of URLs onto prim faces</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PrimMediaMaxRetries</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of retries for media queries.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>PrimMediaRequestQueueDelay</key>
- <map>
- <key>Comment</key>
- <string>Timer delay for fetching media from the queue (in seconds).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>PrimMediaRetryTimerDelay</key>
- <map>
- <key>Comment</key>
- <string>Timer delay for retrying on media queries (in seconds).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>PrimMediaMaxSortedQueueSize</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of objects the viewer will load media for initially</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>100000</integer>
- </map>
- <key>PrimMediaMaxRoundRobinQueueSize</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of objects the viewer will continuously update media for</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>100000</integer>
- </map>
- <key>ProbeHardwareOnStartup</key>
- <map>
- <key>Comment</key>
- <string>Query current hardware configuration on application startup</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>PurgeCacheOnNextStartup</key>
- <map>
- <key>Comment</key>
- <string>Clear local file cache next time viewer is run</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>PurgeCacheOnStartup</key>
- <map>
- <key>Comment</key>
- <string>Clear local file cache every time viewer is run</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>PushToTalkButton</key>
- <map>
- <key>Comment</key>
- <string>Which button or keyboard key is used for push-to-talk</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>MiddleMouse</string>
- </map>
- <key>PushToTalkToggle</key>
- <map>
- <key>Comment</key>
- <string>Should the push-to-talk button behave as a toggle</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>QAMode</key>
- <map>
- <key>Comment</key>
- <string>Enable Testing Features.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>QAModeEventHostPort</key>
- <map>
- <key>Comment</key>
- <string>Port on which lleventhost should listen</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>QAModeTermCode</key>
- <map>
- <key>Comment</key>
- <string>On LL_ERRS, terminate with this code instead of OS message box</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>QuietSnapshotsToDisk</key>
- <map>
- <key>Comment</key>
- <string>Take snapshots to disk without playing animation or sound</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>QuitAfterSeconds</key>
- <map>
- <key>Comment</key>
- <string>The duration allowed before quitting.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>QuitAfterSecondsOfAFK</key>
- <map>
- <key>Comment</key>
- <string>The duration allowed after being AFK before quitting.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>QuitOnLoginActivated</key>
- <map>
- <key>Comment</key>
- <string>Quit if login page is activated (used when auto login is on and users must not be able to login manually)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RadioLandBrushAction</key>
- <map>
- <key>Comment</key>
- <string>Last selected land modification operation (0 = flatten, 1 = raise, 2 = lower, 3 = smooth, 4 = roughen, 5 = revert)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RadioLandBrushSize</key>
- <map>
- <key>Comment</key>
- <string>Size of land modification brush (0 = small, 1 = medium, 2 = large)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LandBrushForce</key>
- <map>
- <key>Comment</key>
- <string>Multiplier for land modification brush force.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>MediaBrowserWindowLimit</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>WebContentWindowLimit</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>5</integer>
- </map>
- <key>MediaRollOffRate</key>
- <map>
- <key>Comment</key>
- <string>Multiplier to change rate of media attenuation</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.125</real>
- </map>
- <key>MediaRollOffMin</key>
- <map>
- <key>Comment</key>
- <string>Adjusts the distance at which media attentuation starts</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>MediaRollOffMax</key>
- <map>
- <key>Comment</key>
- <string>Distance at which media volume is set to 0</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>30.0</real>
- </map>
- <key>RecentItemsSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort key for recent inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RectangleSelectInclusive</key>
- <map>
- <key>Comment</key>
- <string>Select objects that have at least one vertex inside selection rectangle</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RegInClient</key>
- <map>
- <key>Comment</key>
- <string>Experimental: Embed registration in login screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>QuickBuyCurrency</key>
- <map>
- <key>Comment</key>
- <string>Toggle between HTML based currency purchase floater and legacy XUI version</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RegionTextureSize</key>
- <map>
- <key>Comment</key>
- <string>Terrain texture dimensions (power of 2)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>256</integer>
- </map>
- <key>RememberPassword</key>
- <map>
- <key>Comment</key>
- <string>Keep password (in encrypted form) for next login</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderAnisotropic</key>
- <map>
- <key>Comment</key>
- <string>Render textures using anisotropic filtering</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderAppleUseMultGL</key>
- <map>
- <key>Comment</key>
- <string>Whether we want to use multi-threaded OpenGL on Apple hardware (requires restart of SL).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderAttachedLights</key>
- <map>
- <key>Comment</key>
- <string>Render lighted prims that are attached to avatars</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderAttachedParticles</key>
- <map>
- <key>Comment</key>
- <string>Render particle systems that are attached to avatars</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderAvatar</key>
- <map>
- <key>Comment</key>
- <string>Render Avatars</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderAvatarCloth</key>
- <map>
- <key>Comment</key>
- <string>Controls if avatars use wavy cloth</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderAvatarLODFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of avatars (multiplier for current screen area when calculated level of detail)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>RenderAvatarMaxVisible</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of avatars to display at any one time</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>12</integer>
- </map>
- <key>RenderAvatarPhysicsLODFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of avatar physics (such as breast physics).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <integer>1.0</integer>
- </map>
- <key>RenderAvatarVP</key>
- <map>
- <key>Comment</key>
- <string>Use vertex programs to perform hardware skinning of avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderPerformanceTest</key>
- <map>
- <key>Comment</key>
- <string>Disable rendering of everything but in-world content for
- performance testing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderLocalLights</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to render local lights.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <key>RenderShadowNearDist</key>
- <map>
- <key>Comment</key>
- <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>256</real>
- <real>256</real>
- <real>256</real>
- </array>
- </map>
- <key>RenderShadowClipPlanes</key>
- <map>
- <key>Comment</key>
- <string>Near clip plane split distances for shadow map frusta.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>12.0</real>
- <real>32.0</real>
- </array>
- </map>
- <key>RenderShadowSplitExponent</key>
- <map>
- <key>Comment</key>
- <string>Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>3.0</real>
- <real>3.0</real>
- <real>2.0</real>
- </array>
- </map>
- <key>RenderShadowOrthoClipPlanes</key>
- <map>
- <key>Comment</key>
- <string>Near clip plane split distances for orthographic shadow map frusta.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>4.0</real>
- <real>8.0</real>
- <real>24.0</real>
- </array>
- </map>
- <key>RenderShadowProjOffset</key>
- <map>
- <key>Comment</key>
- <string>Amount to scale distance to virtual origin of shadow perspective projection.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>2.0</real>
- </map>
- <key>RenderShadowSlopeThreshold</key>
- <map>
- <key>Comment</key>
- <string>Cutoff slope value for points to affect perspective shadow generation</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>RenderShadowProjExponent</key>
- <map>
- <key>Comment</key>
- <string>Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>RenderSSAOScale</key>
- <map>
- <key>Comment</key>
- <string>Scaling factor for the area to sample for occluders (pixels at 1 meter away, inversely varying with distance)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>500.0</real>
- </map>
- <key>RenderSSAOMaxScale</key>
- <map>
- <key>Comment</key>
- <string>Maximum screen radius for sampling (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>200</integer>
- </map>
- <key>RenderSSAOFactor</key>
- <map>
- <key>Comment</key>
- <string>Occlusion sensitivity factor for ambient occlusion (larger is more)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.30</real>
- </map>
- <key>RenderSSAOEffect</key>
- <map>
- <key>Comment</key>
- <string>Multiplier for (1) value and (2) saturation (HSV definition), for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>0.80</real>
- <real>1.00</real>
- <real>0.00</real>
- </array>
- </map>
- <key>RenderBumpmapMinDistanceSquared</key>
- <map>
- <key>Comment</key>
- <string>Maximum distance at which to render bumpmapped primitives (distance in meters, squared)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>100.0</real>
- </map>
- <key>RenderNormalMapScale</key>
- <map>
- <key>Comment</key>
- <string>Scaler applied to height map when generating normal maps</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>64</real>
- </map>
- <key>RenderCubeMap</key>
- <map>
- <key>Comment</key>
- <string>Whether we can render the cube map or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderDebugAlphaMask</key>
- <map>
- <key>Comment</key>
- <string>Test Alpha Masking Cutoffs.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>RenderDebugGL</key>
- <map>
- <key>Comment</key>
- <string>Enable strict GL debugging.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderDebugNormalScale</key>
- <map>
- <key>Comment</key>
- <string>Scale of normals in debug display.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.03</real>
- </map>
- <key>RenderDebugPipeline</key>
- <map>
- <key>Comment</key>
- <string>Enable strict pipeline debugging.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderDebugTextureBind</key>
- <map>
- <key>Comment</key>
- <string>Enable texture bind performance test.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderDelayCreation</key>
- <map>
- <key>Comment</key>
- <string>Throttle creation of drawables.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderAnimateRes</key>
- <map>
- <key>Comment</key>
- <string>Animate rezing prims.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderBakeSunlight</key>
- <map>
- <key>Comment</key>
- <string>Bake sunlight into vertex buffers for static objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderNoAlpha</key>
- <map>
- <key>Comment</key>
- <string>Disable rendering of alpha objects (render all alpha objects as alpha masks).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderAnimateTrees</key>
- <map>
- <key>Comment</key>
- <string>Use GL matrix ops to animate tree branches.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderGIRange</key>
- <map>
- <key>Comment</key>
- <string>Distance to cut off GI effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>96</real>
- </map>
-
- <key>RenderGILuminance</key>
- <map>
- <key>Comment</key>
- <string>Luminance factor of global illumination contribution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.075</real>
- </map>
-
- <key>RenderGIBrightness</key>
- <map>
- <key>Comment</key>
- <string>Brightness factor of global illumination contribution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.3</real>
- </map>
-
- <key>RenderGINoise</key>
- <map>
- <key>Comment</key>
- <string>Noise of position sampling for GI photon mapping.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.7</real>
- </map>
-
- <key>RenderGIAttenuation</key>
- <map>
- <key>Comment</key>
- <string>Distance attenuation factor for indirect lighting.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
-
- <key>RenderGIBlurBrightness</key>
- <map>
- <key>Comment</key>
- <string>Brightness factor of global illumination blur effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.025</real>
- </map>
-
- <key>RenderGIBlurEdgeWeight</key>
- <map>
- <key>Comment</key>
- <string>Edge weight for GI soften filter (sharpness).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.8</real>
- </map>
-
- <key>RenderGIBlurIncrement</key>
- <map>
- <key>Comment</key>
- <string>Increment of scale for each pass of global illumination blur effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.8</real>
- </map>
-
- <key>RenderLuminanceScale</key>
- <map>
- <key>Comment</key>
- <string>Luminance value scalar for darkening effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
-
- <key>RenderSunLuminanceScale</key>
- <map>
- <key>Comment</key>
- <string>Sun Luminance value scalar for darkening effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
-
- <key>RenderSunLuminanceOffset</key>
- <map>
- <key>Comment</key>
- <string>Sun Luminance value offset for darkening effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0</real>
- </map>
-
- <key>RenderLuminanceDetail</key>
- <map>
- <key>Comment</key>
- <string>Mipmap level to use for luminance</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>16.0</real>
- </map>
-
- <key>RenderMinimumLODTriangleCount</key>
- <map>
- <key>Comment</key>
- <string>Triangle count threshold at which automatic LOD generation stops</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>16</real>
- </map>
-
- <key>RenderEdgeDepthCutoff</key>
- <map>
- <key>Comment</key>
- <string>Cutoff for depth difference that amounts to an edge.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.01</real>
- </map>
- <key>RenderEdgeNormCutoff</key>
- <map>
- <key>Comment</key>
- <string>Cutoff for normal difference that amounts to an edge.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
-
- <key>RenderDeferredAlphaSoften</key>
- <map>
- <key>Comment</key>
- <string>Scalar for softening alpha surfaces (for soft particles).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.75</real>
- </map>
- <key>RenderDeferredNoise</key>
- <map>
- <key>Comment</key>
- <string>Noise scalar to hide banding in deferred render.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4</real>
- </map>
- <key>RenderDeferredSpotShadowBias</key>
- <map>
- <key>Comment</key>
- <string>Bias value for spot shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>-64.0</real>
- </map>
- <key>RenderDeferredSpotShadowOffset</key>
- <map>
- <key>Comment</key>
- <string>Offset value for spot shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.8</real>
- </map>
-
- <key>RenderShadowBias</key>
- <map>
- <key>Comment</key>
- <string>Bias value for shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>-0.008</real>
- </map>
- <key>RenderShadowOffset</key>
- <map>
- <key>Comment</key>
- <string>Offset value for shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.01</real>
- </map>
- <key>RenderShadowBiasError</key>
- <map>
- <key>Comment</key>
- <string>Error scale for shadow bias (based on altitude).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0</real>
- </map>
- <key>RenderShadowOffsetError</key>
- <map>
- <key>Comment</key>
- <string>Error scale for shadow offset (based on altitude).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0</real>
- </map>
-
- <key>RenderDepthOfField</key>
- <map>
- <key>Comment</key>
- <string>Whether to use depth of field effect when lighting and shadows are enabled</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderSpotLightsInNondeferred</key>
- <map>
- <key>Comment</key>
- <string>Whether to support projectors as spotlights when Lighting and Shadows is disabled</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderSpotShadowBias</key>
- <map>
- <key>Comment</key>
- <string>Bias value for shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>-0.001</real>
- </map>
- <key>RenderSpotShadowOffset</key>
- <map>
- <key>Comment</key>
- <string>Offset value for shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.04</real>
- </map>
-
- <key>RenderShadowResolutionScale</key>
- <map>
- <key>Comment</key>
- <string>Scale of shadow map resolution vs. screen resolution</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
-
- <key>RenderDeferredTreeShadowBias</key>
- <map>
- <key>Comment</key>
- <string>Bias value for tree shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderDeferredTreeShadowOffset</key>
- <map>
- <key>Comment</key>
- <string>Offset value for tree shadows (prevent shadow acne).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
-
- <key>RenderHoverGlowEnable</key>
- <map>
- <key>Comment</key>
- <string>Show glow effect when hovering on interactive objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderHighlightFadeTime</key>
- <map>
- <key>Comment</key>
- <string>Transition time for mouseover highlights.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
-
- <key>RenderHighlightBrightness</key>
- <map>
- <key>Comment</key>
- <string>Brightness of mouseover highlights.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4.0</real>
- </map>
-
- <key>RenderHighlightThickness</key>
- <map>
- <key>Comment</key>
- <string>Thickness of mouseover highlights.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.6</real>
- </map>
-
- <key>RenderHighlightColor</key>
- <map>
- <key>Comment</key>
- <string>Brightness of mouseover highlights.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color4</string>
- <key>Value</key>
- <array>
- <real>0.4</real>
- <real>0.98</real>
- <real>0.93</real>
- <real>1.0</real>
- </array>
- </map>
-
- <key>RenderSpecularResX</key>
- <map>
- <key>Comment</key>
- <string>Spec map resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>128</real>
- </map>
-
- <key>RenderSpecularResY</key>
- <map>
- <key>Comment</key>
- <string>Spec map resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>128</real>
- </map>
-
- <key>RenderSpecularExponent</key>
- <map>
- <key>Comment</key>
- <string>Specular exponent for generating spec map</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>8</real>
- </map>
-
- <key>RenderDeferred</key>
- <map>
- <key>Comment</key>
- <string>Use deferred rendering pipeline.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderDeferredGI</key>
- <map>
- <key>Comment</key>
- <string>Enable GI in deferred renderer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
-
- <key>RenderDeferredSun</key>
- <map>
- <key>Comment</key>
- <string>Execute sunlight shader in deferred renderer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <key>RenderDeferredAtmospheric</key>
- <map>
- <key>Comment</key>
- <string>Execute atmospheric shader in deferred renderer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <key>RenderDeferredSSAO</key>
- <map>
- <key>Comment</key>
- <string>Execute screen space ambient occlusion shader in deferred renderer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <key>RenderDeferredBlurLight</key>
- <map>
- <key>Comment</key>
- <string>Execute shadow softening shader in deferred renderer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <key>RenderDeferredSunWash</key>
- <map>
- <key>Comment</key>
- <string>Amount local lights are washed out by sun.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>RenderShadowNoise</key>
- <map>
- <key>Comment</key>
- <string>Magnitude of noise on shadow samples.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>-0.0001</real>
- </map>
- <key>RenderShadowErrorCutoff</key>
- <map>
- <key>Comment</key>
- <string>Cutoff error value to use ortho instead of perspective projection.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>RenderShadowFOVCutoff</key>
- <map>
- <key>Comment</key>
- <string>Cutoff FOV to use ortho instead of perspective projection.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.1</real>
- </map>
-
- <key>RenderShadowGaussian</key>
- <map>
- <key>Comment</key>
- <string>Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>3.0</real>
- <real>2.0</real>
- <real>0.0</real>
- </array>
- </map>
-
- <key>RenderShadowBlurSize</key>
- <map>
- <key>Comment</key>
- <string>Scale of shadow softening kernel.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.4</real>
- </map>
- <key>RenderShadowBlurSamples</key>
- <map>
- <key>Comment</key>
- <string>Number of samples to take for each pass of shadow blur (value range 1-16). Actual number of samples is value * 2 - 1.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>4</real>
- </map>
- <key>RenderShadowBlurDistFactor</key>
- <map>
- <key>Comment</key>
- <string>Distance scaler for shadow blur.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0</real>
- </map>
-
- <key>RenderGIAmbiance</key>
- <map>
- <key>Comment</key>
- <string>Ambiance factor of global illumination contribution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
-
- <key>RenderGIMinRenderSize</key>
- <map>
- <key>Comment</key>
- <string>Minimum size of objects to put into GI source map.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
-
- <key>RenderGIBlurColorCurve</key>
- <map>
- <key>Comment</key>
- <string>Color curve for GI softening kernel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.6</real>
- <real>0.02</real>
- </array>
- </map>
-
- <key>RenderGIBlurPasses</key>
- <map>
- <key>Comment</key>
- <string>Scale of GI softening kernel.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>4</real>
- </map>
-
- <key>RenderGIBlurSize</key>
- <map>
- <key>Comment</key>
- <string>Scale of GI softening kernel.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4.0</real>
- </map>
- <key>RenderGIBlurSamples</key>
- <map>
- <key>Comment</key>
- <string>Number of samples to take for each pass of GI blur (value range 1-16). Actual number of samples is value * 2 - 1.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <real>16</real>
- </map>
- <key>RenderGIBlurDistFactor</key>
- <map>
- <key>Comment</key>
- <string>Distance scaler for GI blur.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
-
- <key>RenderDynamicLOD</key>
- <map>
- <key>Comment</key>
- <string>Dynamically adjust level of detail.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderFSAASamples</key>
- <map>
- <key>Comment</key>
- <string>Number of samples to use for FSAA (0 = no AA).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderFarClip</key>
- <map>
- <key>Comment</key>
- <string>Distance of far clip plane from camera (meters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>256.0</real>
- </map>
- <key>RenderAutoMaskAlphaNonDeferred</key>
- <map>
- <key>Comment</key>
- <string>Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderAutoMaskAlphaDeferred</key>
- <map>
- <key>Comment</key>
- <string>Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderFlexTimeFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of flexible objects (multiplier for amount of time spent processing flex objects)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderFogRatio</key>
- <map>
- <key>Comment</key>
- <string>Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4.0</real>
- </map>
- <key>RenderGamma</key>
- <map>
- <key>Comment</key>
- <string>Sets gamma exponent for renderer</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>RenderGammaFull</key>
- <map>
- <key>Comment</key>
- <string>Use fully controllable gamma correction, instead of faster, hard-coded gamma correction of 2.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderGlow</key>
- <map>
- <key>Comment</key>
- <string>Render bloom post effect.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderGlowIterations</key>
- <map>
- <key>Comment</key>
- <string>Number of times to iterate the glow (higher = wider and smoother but slower)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>RenderGlowLumWeights</key>
- <map>
- <key>Comment</key>
- <string>Weights for each color channel to be used in calculating luminance (should add up to 1.0)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>1</real>
- <real>0</real>
- <real>0</real>
- </array>
- </map>
- <key>RenderGlowMaxExtractAlpha</key>
- <map>
- <key>Comment</key>
- <string>Max glow alpha value for brightness extraction to auto-glow.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>RenderGlowMinLuminance</key>
- <map>
- <key>Comment</key>
- <string>Min luminance intensity necessary to consider an object bright enough to automatically glow.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>9999</real>
- </map>
- <key>RenderGlowResolutionPow</key>
- <map>
- <key>Comment</key>
- <string>Glow map resolution power of two.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>9</integer>
- </map>
- <key>RenderGlowStrength</key>
- <map>
- <key>Comment</key>
- <string>Additive strength of glow.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.35</real>
- </map>
- <key>RenderGlowWarmthAmount</key>
- <map>
- <key>Comment</key>
- <string>Amount of warmth extraction to use (versus luminance extraction). 0 = lum, 1.0 = warmth</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>RenderGlowWarmthWeights</key>
- <map>
- <key>Comment</key>
- <string>Weight of each color channel used before finding the max warmth</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.5</real>
- <real>0.7</real>
- </array>
- </map>
- <key>RenderGlowWidth</key>
- <map>
- <key>Comment</key>
- <string>Glow sample size (higher = wider and softer but eventually more pixelated)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.3</real>
- </map>
- <key>RenderGround</key>
- <map>
- <key>Comment</key>
- <string>Determines whether we can render the ground pool or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderHUDInSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Display HUD attachments in snapshot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderHUDParticles</key>
- <map>
- <key>Comment</key>
- <string>Display particle systems in HUD attachments (experimental)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderHighlightSelections</key>
- <map>
- <key>Comment</key>
- <string>Show selection outlines on objects</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderHiddenSelections</key>
- <map>
- <key>Comment</key>
- <string>Show selection lines on objects that are behind other objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderHideGroupTitle</key>
- <map>
- <key>Comment</key>
- <string>Don't show my group title in my name label</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NameTagShowGroupTitles</key>
- <map>
- <key>Comment</key>
- <string>Show group titles in name labels</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NameTagShowDisplayNames</key>
- <map>
- <key>Comment</key>
- <string>Show display names in name labels</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>NameTagShowFriends</key>
- <map>
- <key>Comment</key>
- <string>Highlight the name tags of your friends</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NameTagShowUsernames</key>
- <map>
- <key>Comment</key>
- <string>Show usernames in avatar name tags</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderInitError</key>
- <map>
- <key>Comment</key>
- <string>Error occured while initializing GL</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderLightRadius</key>
- <map>
- <key>Comment</key>
- <string>Render the radius of selected lights</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderMaxPartCount</key>
- <map>
- <key>Comment</key>
- <string>Maximum number of particles to display on screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4096</integer>
- </map>
- <key>RenderMaxNodeSize</key>
- <map>
- <key>Comment</key>
- <string>Maximum size of a single node's vertex data (in KB).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>8192</integer>
- </map>
- <key>RenderMaxVBOSize</key>
- <map>
- <key>Comment</key>
- <string>Maximum size of a vertex buffer (in KB).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>512</integer>
- </map>
- <key>RenderNameFadeDuration</key>
- <map>
- <key>Comment</key>
- <string>Time interval over which to fade avatar names (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderNameShowSelf</key>
- <map>
- <key>Comment</key>
- <string>Display own name above avatar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderNameShowTime</key>
- <map>
- <key>Comment</key>
- <string>Fade avatar names after specified time (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>RenderObjectBump</key>
- <map>
- <key>Comment</key>
- <string>Show bumpmapping on primitives</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderQualityPerformance</key>
- <map>
- <key>Comment</key>
- <string>Which graphics settings you've chosen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderReflectionDetail</key>
- <map>
- <key>Comment</key>
- <string>Detail of reflection render pass.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>RenderShadowDetail</key>
- <map>
- <key>Comment</key>
- <string>Detail of shadows.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
-
- <key>RenderReflectionRes</key>
- <map>
- <key>Comment</key>
- <string>Reflection map resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>64</integer>
- </map>
- <key>RenderResolutionDivisor</key>
- <map>
- <key>Comment</key>
- <string>Divisor for rendering 3D scene at reduced resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderShaderLightingMaxLevel</key>
- <map>
- <key>Comment</key>
- <string>Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>RenderShaderLODThreshold</key>
- <map>
- <key>Comment</key>
- <string>Fraction of draw distance defining the switch to a different shader LOD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderShaderParticleThreshold</key>
- <map>
- <key>Comment</key>
- <string>Fraction of draw distance to not use shader on particles</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>RenderSunDynamicRange</key>
- <map>
- <key>Comment</key>
- <string>Defines what percent brighter the sun is than local point lights (1.0 = 100% brighter. Value should not be less than 0. ).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderTerrainDetail</key>
- <map>
- <key>Comment</key>
- <string>Detail applied to terrain texturing (0 = none, 1 or 2 = full)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>RenderTerrainLODFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of terrain (multiplier for current screen area when calculated level of detail)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderTerrainScale</key>
- <map>
- <key>Comment</key>
- <string>Terrain detail texture scale</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>12.0</real>
- </map>
- <key>RenderTextureMemoryMultiple</key>
- <map>
- <key>Comment</key>
- <string>Multiple of texture memory value to use (should fit: 0 &lt; value &lt;= 1.0)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderTrackerBeacon</key>
- <map>
- <key>Comment</key>
- <string>Display tracking arrow and beacon to target avatar, teleport destination</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderTransparentWater</key>
- <map>
- <key>Comment</key>
- <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderTreeLODFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of vegetation (multiplier for current screen area when calculated level of detail)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>RenderUIInSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Display user interface in snapshot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderUIBuffer</key>
- <map>
- <key>Comment</key>
- <string>Cache ui render in a screen aligned buffer.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderUnloadedAvatar</key>
- <map>
- <key>Comment</key>
- <string>Show avatars which haven't finished loading</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderUseTriStrips</key>
- <map>
- <key>Comment</key>
- <string>Use triangle strips for rendering prims.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderUseTriStrips</key>
- <map>
- <key>Comment</key>
- <string>Use triangle strips for rendering prims.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderUseFarClip</key>
- <map>
- <key>Comment</key>
- <string>If false, frustum culling will ignore far clip plane.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderUseImpostors</key>
- <map>
- <key>Comment</key>
- <string>Whether we want to use impostors for far away avatars.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderUseShaderLOD</key>
- <map>
- <key>Comment</key>
- <string>Whether we want to have different shaders for LOD</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderUseShaderNearParticles</key>
- <map>
- <key>Comment</key>
- <string>Whether we want to use shaders on near particles</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderVBOEnable</key>
- <map>
- <key>Comment</key>
- <string>Use GL Vertex Buffer Objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderVBOMappingDisable</key>
- <map>
- <key>Comment</key>
- <string>Disable VBO glMapBufferARB</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderUseStreamVBO</key>
- <map>
- <key>Comment</key>
- <string>Use VBO's for stream buffers</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderPreferStreamDraw</key>
- <map>
- <key>Comment</key>
- <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RenderVolumeLODFactor</key>
- <map>
- <key>Comment</key>
- <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>RenderWater</key>
- <map>
- <key>Comment</key>
- <string>Display water</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderWaterMipNormal</key>
- <map>
- <key>Comment</key>
- <string>Use mip maps for water normal map.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderWaterRefResolution</key>
- <map>
- <key>Comment</key>
- <string>Water planar reflection resolution.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>512</integer>
- </map>
- <key>RenderParcelSelection</key>
- <map>
- <key>Comment</key>
- <string>Display selected parcel outline</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RotateRight</key>
- <map>
- <key>Comment</key>
- <string>Make the agent rotate to its right.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>RotationStep</key>
- <map>
- <key>Comment</key>
- <string>All rotations via rotation tool are constrained to multiples of this unit (degrees)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>MeshStreamingCostScaler</key>
- <map>
- <key>Comment</key>
- <string>DEBUG</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3.0</real>
- </map>
- <key>MeshThreadCount</key>
- <map>
- <key>Comment</key>
- <string>Number of threads to use for loading meshes.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>8</integer>
- </map>
- <key>MeshMaxConcurrentRequests</key>
- <map>
- <key>Comment</key>
- <string>Number of threads to use for loading meshes.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>32</integer>
- </map>
- <key>RunMultipleThreads</key>
- <map>
- <key>Comment</key>
- <string>If TRUE keep background threads active during render</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SafeMode</key>
- <map>
- <key>Comment</key>
- <string>Reset preferences, run in safe mode.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SaveMinidump</key>
- <map>
- <key>Comment</key>
- <string>Save minidump for developer debugging on crash</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ScaleShowAxes</key>
- <map>
- <key>Comment</key>
- <string>Show indicator of selected scale axis when scaling</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ScaleStretchTextures</key>
- <map>
- <key>Comment</key>
- <string>Stretch textures along with object when scaling</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ScaleUniform</key>
- <map>
- <key>Comment</key>
- <string>Scale selected objects evenly about center of selection</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ScriptHelpFollowsCursor</key>
- <map>
- <key>Comment</key>
- <string>Scripting help window updates contents based on script editor contents under text cursor</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ScriptsCanShowUI</key>
- <map>
- <key>Comment</key>
- <string>Allow LSL calls (such as LLMapDestination) to spawn viewer UI</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>SecondLifeEnterprise</key>
- <map>
- <key>Comment</key>
- <string>Enables Second Life Enterprise features</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SelectMovableOnly</key>
- <map>
- <key>Comment</key>
- <string>Select only objects you can move</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SelectOwnedOnly</key>
- <map>
- <key>Comment</key>
- <string>Select only objects you own</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SelectionHighlightAlpha</key>
- <map>
- <key>Comment</key>
- <string>Opacity of selection highlight (0.0 = completely transparent, 1.0 = completely opaque)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.40000000596</real>
- </map>
- <key>SelectionHighlightAlphaTest</key>
- <map>
- <key>Comment</key>
- <string>Alpha value below which pixels are displayed on selection highlight line (0.0 = show all pixels, 1.0 = show now pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>SelectionHighlightThickness</key>
- <map>
- <key>Comment</key>
- <string>Thickness of selection highlight line (fraction of view distance)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.00999999977648</real>
- </map>
- <key>SelectionHighlightUAnim</key>
- <map>
- <key>Comment</key>
- <string>Rate at which texture animates along U direction in selection highlight line (fraction of texture per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.0</real>
- </map>
- <key>SelectionHighlightUScale</key>
- <map>
- <key>Comment</key>
- <string>Scale of texture display on selection highlight line (fraction of texture size)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.1</real>
- </map>
- <key>SelectionHighlightVAnim</key>
- <map>
- <key>Comment</key>
- <string>Rate at which texture animates along V direction in selection highlight line (fraction of texture per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>SelectionHighlightVScale</key>
- <map>
- <key>Comment</key>
- <string>Scale of texture display on selection highlight line (fraction of texture size)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>ServerChoice</key>
- <map>
- <key>Comment</key>
- <string>[DO NOT MODIFY] Controls which grid you connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShareWithGroup</key>
- <map>
- <key>Comment</key>
- <string>Newly created objects are shared with the currently active group</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdvancedGraphicsSettings</key>
- <map>
- <key>Comment</key>
- <string>Show advanced graphics settings</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAllObjectHoverTip</key>
- <map>
- <key>Comment</key>
- <string>Show descriptive tooltip when mouse hovers over non-interactive and interactive objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AvatarNameTagMode</key>
- <map>
- <key>Comment</key>
- <string>Select Avatar Name Tag Mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowAxes</key>
- <map>
- <key>Comment</key>
- <string>Render coordinate frame at your position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowBanLines</key>
- <map>
- <key>Comment</key>
- <string>Show in-world ban/access borders</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowBuildButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Build button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowCameraButton</key>
- <map>
- <key>Comment</key>
- <string>Show/Hide View button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowConsoleWindow</key>
- <map>
- <key>Comment</key>
- <string>Show log in separate OS window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NavBarShowCoordinates</key>
- <map>
- <key>Comment</key>
- <string>Show coordinates in navigation bar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NavBarShowParcelProperties</key>
- <map>
- <key>Comment</key>
- <string>Show parcel property icons in navigation bar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowBetaGrids</key>
- <map>
- <key>Comment</key>
- <string>Display the beta grids in the grid selection control.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowCrosshairs</key>
- <map>
- <key>Comment</key>
- <string>Display crosshairs when in mouselook mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowDebugConsole</key>
- <map>
- <key>Comment</key>
- <string>Show log in SL window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowEmptyFoldersWhenSearching</key>
- <map>
- <key>Comment</key>
- <string>Shows folders that do not have any visible contents when applying a filter to inventory</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowGestureButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Gesture button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowHoverTips</key>
- <map>
- <key>Comment</key>
- <string>Show descriptive tooltip when mouse hovers over items in world</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowLandHoverTip</key>
- <map>
- <key>Comment</key>
- <string>Show descriptive tooltip when mouse hovers over land</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowMiniMapButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Mini-Map button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowMoveButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Move button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowScriptErrors</key>
- <map>
- <key>Comment</key>
- <string>Show script errors</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowScriptErrorsLocation</key>
- <map>
- <key>Comment</key>
- <string>Show script error in chat or window</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowSearchButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Search button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowSnapshotButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Snapshot button button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowObjectRenderingCost</key>
- <map>
- <key>Comment</key>
- <string>Show the object rendering cost in build tools</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowNavbarFavoritesPanel</key>
- <map>
- <key>Comment</key>
- <string>Show/Hide Navigation Bar Favorites Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowNavbarNavigationPanel</key>
- <map>
- <key>Comment</key>
- <string>Show/Hide Navigation Bar Navigation Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowWorldMapButton</key>
- <map>
- <key>Comment</key>
- <string>Shows/Hides Map button in the bottom tray.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowMiniLocationPanel</key>
- <map>
- <key>Comment</key>
- <string>Show/Hide Mini-Location Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SidebarCameraMovement</key>
- <map>
- <key>Comment</key>
- <string>Reflects world rect changing while changing sidebar visibility.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>GroupListShowIcons</key>
- <map>
- <key>Comment</key>
- <string>Show/hide group icons in the group list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FriendsListShowIcons</key>
- <map>
- <key>Comment</key>
- <string>Show/hide online and all friends icons in the friend list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FriendsListShowPermissions</key>
- <map>
- <key>Comment</key>
- <string>Show/hide permission icons in the friend list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>NearbyListShowIcons</key>
- <map>
- <key>Comment</key>
- <string>Show/hide people icons in nearby list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RecentListShowIcons</key>
- <map>
- <key>Comment</key>
- <string>Show/hide people icons in recent list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>FriendsSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort order for friends (0 = by name, 1 = by online status)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>NearbyPeopleSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort order for nearby people (0 = by name, 3 = by distance, 4 = by most recent)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>RecentPeopleSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort order for recent people (0 = by name, 2 = by most recent)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>ShowPGSearchAll</key>
- <map>
- <key>Comment</key>
- <string>Display results of search All that are flagged as general</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureSearchAll</key>
- <map>
- <key>Comment</key>
- <string>Display results of search All that are flagged as moderate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultSearchAll</key>
- <map>
- <key>Comment</key>
- <string>Display results of search All that are flagged as adult</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPGGroups</key>
- <map>
- <key>Comment</key>
- <string>Display results of find groups that are flagged as general</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureGroups</key>
- <map>
- <key>Comment</key>
- <string>Display results of find groups that are flagged as moderate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultGroups</key>
- <map>
- <key>Comment</key>
- <string>Display results of find groups that are flagged as adult</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPGClassifieds</key>
- <map>
- <key>Comment</key>
- <string>Display results of find classifieds that are flagged as general</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureClassifieds</key>
- <map>
- <key>Comment</key>
- <string>Display results of find classifieds that are flagged as moderate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultClassifieds</key>
- <map>
- <key>Comment</key>
- <string>Display results of find classifieds that are flagged as adult</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPGEvents</key>
- <map>
- <key>Comment</key>
- <string>Display results of find events that are flagged as general</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureEvents</key>
- <map>
- <key>Comment</key>
- <string>Display results of find events that are flagged as moderate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultEvents</key>
- <map>
- <key>Comment</key>
- <string>Display results of find events that are flagged as adult</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPGLand</key>
- <map>
- <key>Comment</key>
- <string>Display results of find land sales that are flagged as general</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureLand</key>
- <map>
- <key>Comment</key>
- <string>Display results of find land sales that are flagged as moderate</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultLand</key>
- <map>
- <key>Comment</key>
- <string>Display results of find land sales that are flagged as adult</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPGSims</key>
- <map>
- <key>Comment</key>
- <string>Display results of find places or find popular that are in general sims</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowMatureSims</key>
- <map>
- <key>Comment</key>
- <string>Display results of find places or find popular that are in moderate sims</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowAdultSims</key>
- <map>
- <key>Comment</key>
- <string>Display results of find places or find popular that are in adult sims</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>HideFromEditor</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowNearClip</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowNewInventory</key>
- <map>
- <key>Comment</key>
- <string>Automatically views new notecards/textures/landmarks</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowInInventory</key>
- <map>
- <key>Comment</key>
- <string>Automatically opens inventory to show accepted objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowObjectUpdates</key>
- <map>
- <key>Comment</key>
- <string>Show when update messages are received for individual objects</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowOverlayTitle</key>
- <map>
- <key>Comment</key>
- <string>Prints watermark text message on screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowParcelOwners</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPermissions</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowPropertyLines</key>
- <map>
- <key>Comment</key>
- <string>Show line overlay demarking property boundaries</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowNetStats</key>
- <map>
- <key>Comment</key>
- <string>Show the Search Bar in the Status Overlay</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowSelectionBeam</key>
- <map>
- <key>Comment</key>
- <string>Show selection particle beam when selecting or interacting with objects.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowStartLocation</key>
- <map>
- <key>Comment</key>
- <string>Display starting location menu on login screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowTangentBasis</key>
- <map>
- <key>Comment</key>
- <string>Render normal and binormal (debugging bump mapping)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowToolBar</key>
- <map>
- <key>Comment</key>
- <string>Show toolbar at bottom of screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowTutorial</key>
- <map>
- <key>Comment</key>
- <string>Show tutorial window on login</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowVoiceVisualizersInCalls</key>
- <map>
- <key>Comment</key>
- <string>Enables in-world voice visualizers, voice gestures and lip-sync while in group or P2P calls.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SkinCurrent</key>
- <map>
- <key>Comment</key>
- <string>The currently selected skin.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>default</string>
- </map>
- <key>SkinningSettingsFile</key>
- <map>
- <key>Comment</key>
- <string>Client skin color setting file name (per install).</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>SkyAmbientScale</key>
- <map>
- <key>Comment</key>
- <string>Controls strength of ambient, or non-directional light from the sun and moon (fraction or multiple of default ambient level)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.300000011921</real>
- </map>
- <key>SkyEditPresets</key>
- <map>
- <key>Comment</key>
- <string>Whether to be able to edit the sky defaults or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SkyNightColorShift</key>
- <map>
- <key>Comment</key>
- <string>Controls moonlight color (base color applied to moon as light source)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Color3</string>
- <key>Value</key>
- <array>
- <real>0.67</real>
- <real>0.67</real>
- <real>1.0</real>
- </array>
- </map>
- <key>SkyOverrideSimSunPosition</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SkySunDefaultPosition</key>
- <map>
- <key>Comment</key>
- <string>Default position of sun in sky (direction in world coordinates)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Vector3</string>
- <key>Value</key>
- <array>
- <real>1.0</real>
- <real>0.0</real>
- <real>0.1</real>
- </array>
- </map>
- <key>SkyUseClassicClouds</key>
- <map>
- <key>Comment</key>
- <string>Whether to use the old Second Life particle clouds or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>SnapEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable snapping to grid</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>SnapMargin</key>
- <map>
- <key>Comment</key>
- <string>Controls maximum distance between windows before they auto-snap together (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>SnapToMouseCursor</key>
- <map>
- <key>Comment</key>
- <string>When snapping to grid, center object on nearest grid point to mouse cursor</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SnapshotFormat</key>
- <map>
- <key>Comment</key>
- <string>Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SnapshotLocalLastResolution</key>
- <map>
- <key>Comment</key>
- <string>Take next local snapshot at this resolution</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SnapshotPostcardLastResolution</key>
- <map>
- <key>Comment</key>
- <string>Take next postcard snapshot at this resolution</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SnapshotQuality</key>
- <map>
- <key>Comment</key>
- <string>Quality setting of postcard JPEGs (0 = worst, 100 = best)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>75</integer>
- </map>
- <key>SnapshotSharingEnabled</key>
- <map>
- <key>Comment</key>
- <string>Enable uploading of snapshots to a web service.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SnapshotConfigURL</key>
- <map>
- <key>Comment</key>
- <string>URL to fetch Snapshot Sharing configuration data from.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>http://photos.apps.staging.avatarsunited.com/viewer_config</string>
- </map>
- <key>SnapshotTextureLastResolution</key>
- <map>
- <key>Comment</key>
- <string>Take next texture snapshot at this resolution</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SpeedTest</key>
- <map>
- <key>Comment</key>
- <string>Performance testing mode, no network</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>StatsAutoRun</key>
- <map>
- <key>Comment</key>
- <string>Play back autopilot</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>StatsFile</key>
- <map>
- <key>Comment</key>
- <string>Filename for stats logging output</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>fs.txt</string>
- </map>
- <key>StatsNumRuns</key>
- <map>
- <key>Comment</key>
- <string>Loop autopilot playback this number of times</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>StatsPilotFile</key>
- <map>
- <key>Comment</key>
- <string>Filename for stats logging autopilot path</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>pilot.txt</string>
- </map>
- <key>StatsPilotXMLFile</key>
- <map>
- <key>Comment</key>
- <string>Filename for stats logging extended autopilot path</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>pilot.xml</string>
- </map>
- <key>StatsQuitAfterRuns</key>
- <map>
- <key>Comment</key>
- <string>Quit application after this number of autopilot playback runs</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>StatsSessionTrackFrameStats</key>
- <map>
- <key>Comment</key>
- <string>Track rendering and network statistics</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>StatsSummaryFile</key>
- <map>
- <key>Comment</key>
- <string>Filename for stats logging summary</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>fss.txt</string>
- </map>
- <key>SystemLanguage</key>
- <map>
- <key>Comment</key>
- <string>Language indicated by system settings (for UI)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>en</string>
- </map>
- <key>TabToTextFieldsOnly</key>
- <map>
- <key>Comment</key>
- <string>TAB key takes you to next text entry field, instead of next widget</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TerrainColorHeightRange</key>
- <map>
- <key>Comment</key>
- <string>Altitude range over which a given terrain texture has effect (meters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>60.0</real>
- </map>
- <key>TerrainColorStartHeight</key>
- <map>
- <key>Comment</key>
- <string>Starting altitude for terrain texturing (meters)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>20.0</real>
- </map>
- <key>TextureDecodeDisabled</key>
- <map>
- <key>Comment</key>
- <string>If TRUE, do not fetch and decode any textures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TextureDisable</key>
- <map>
- <key>Comment</key>
- <string>If TRUE, do not load textures for in-world content</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TextureDiscardLevel</key>
- <map>
- <key>Comment</key>
- <string>Specify texture resolution (0 = highest, 5 = lowest)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TextureLoadFullRes</key>
- <map>
- <key>Comment</key>
- <string>If TRUE, always load textures at full resolution (discard = 0)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TextureMemory</key>
- <map>
- <key>Comment</key>
- <string>Amount of memory to use for textures in MB (0 = autodetect)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TexturePickerShowFolders</key>
- <map>
- <key>Comment</key>
- <string>Show folders with no texures in texture picker</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>TexturePickerSortOrder</key>
- <map>
- <key>Comment</key>
- <string>Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>ThrottleBandwidthKBPS</key>
- <map>
- <key>Comment</key>
- <string>Maximum allowable downstream bandwidth (kilo bits per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>500.0</real>
- </map>
- <key>UpdaterMaximumBandwidth</key>
- <map>
- <key>Comment</key>
- <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>500.0</real>
- </map>
- <key>ToolTipDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before displaying tooltip when mouse stops over UI element</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.699999988079</real>
- </map>
- <key>ToolTipFadeTime</key>
- <map>
- <key>Comment</key>
- <string>Seconds over which tooltip fades away</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.2</real>
- </map>
- <key>ToolTipVisibleTimeFar</key>
- <map>
- <key>Comment</key>
- <string>Fade tooltip after after time passes (seconds) while mouse not near tooltip</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>ToolTipVisibleTimeNear</key>
- <map>
- <key>Comment</key>
- <string>Fade tooltip after after time passes (seconds) while mouse near tooltip or original position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>ToolTipVisibleTimeOver</key>
- <map>
- <key>Comment</key>
- <string>Fade tooltip after after time passes (seconds) while mouse over tooltip</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1000.0</real>
- </map>
- <key>ToolboxAutoMove</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TrackFocusObject</key>
- <map>
- <key>Comment</key>
- <string>Camera tracks last object zoomed on</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>TranslateLanguage</key>
- <map>
- <key>Comment</key>
- <string>Translate Language specifier</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>default</string>
- </map>
- <key>TranslateChat</key>
- <map>
- <key>Comment</key>
- <string>Translate incoming chat messages</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TutorialURL</key>
- <map>
- <key>Comment</key>
- <string>URL for tutorial menu item, set automatically during login</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>TypeAheadTimeout</key>
- <map>
- <key>Comment</key>
- <string>Time delay before clearing type-ahead buffer in lists (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.5</real>
- </map>
- <key>UIAutoScale</key>
- <map>
- <key>Comment</key>
- <string>Keep UI scale consistent across different resolutions</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UIAvatariconctrlSymbolHPad</key>
- <map>
- <key>Comment</key>
- <string>UI Avatar Icon Control Symbol Horizontal Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>2</real>
- </map>
- <key>UIAvatariconctrlSymbolVPad</key>
- <map>
- <key>Comment</key>
- <string>UI Avatar Icon Control Symbol Vertical Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>2</real>
- </map>
- <key>UIAvatariconctrlSymbolSize</key>
- <map>
- <key>Comment</key>
- <string>UI Avatar Icon Control Symbol Size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>5</real>
- </map>
- <key>UIAvatariconctrlSymbolPosition</key>
- <map>
- <key>Comment</key>
- <string>UI Avatar Icon Control Symbol Position (TopLeft|TopRight|BottomLeft|BottomRight)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>BottomRight</string>
- </map>
- <key>UIButtonOrigHPad</key>
- <map>
- <key>Comment</key>
- <string>UI Button Original Horizontal Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>6</real>
- </map>
- <key>UICheckboxctrlBtnSize</key>
- <map>
- <key>Comment</key>
- <string>UI Checkbox Control Button Size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>13</real>
- </map>
- <key>UICheckboxctrlHeight</key>
- <map>
- <key>Comment</key>
- <string>UI Checkbox Control Height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>16</real>
- </map>
- <key>UICheckboxctrlHPad</key>
- <map>
- <key>Comment</key>
- <string>UI Checkbox Control Horizontal Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>2</real>
- </map>
- <key>UICheckboxctrlSpacing</key>
- <map>
- <key>Comment</key>
- <string>UI Checkbox Control Spacing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>5</real>
- </map>
- <key>UICheckboxctrlVPad</key>
- <map>
- <key>Comment</key>
- <string>UI Checkbox Control Vertical Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>2</real>
- </map>
- <key>UICloseBoxFromTop</key>
- <map>
- <key>Comment</key>
- <string>Distance from top of floater to top of close box icon, pixels</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>5</real>
- </map>
- <key>UIExtraTriangleHeight</key>
- <map>
- <key>Comment</key>
- <string>UI extra triangle height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>-2</real>
- </map>
- <key>UIExtraTriangleWidth</key>
- <map>
- <key>Comment</key>
- <string>UI extra triangle width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>2</real>
- </map>
- <key>UIFloaterCloseBoxSize</key>
- <map>
- <key>Comment</key>
- <string>Size of UI floater close box size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>16</real>
- </map>
- <key>UIFloaterHPad</key>
- <map>
- <key>Comment</key>
- <string>Size of UI floater horizontal pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>6</real>
- </map>
- <key>UIFloaterTestBool</key>
- <map>
- <key>Comment</key>
- <string>Example saved setting for the test floater</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UIFloaterTitleVPad</key>
- <map>
- <key>Comment</key>
- <string>Distance from top of floater to top of title string, pixels</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>7</real>
- </map>
- <key>UIImgDefaultEyesUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>6522e74d-1660-4e7f-b601-6f48c1659a77</string>
- </map>
- <key>UIImgDefaultGlovesUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultHairUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>7ca39b4c-bd19-4699-aff7-f93fd03d3e7b</string>
- </map>
- <key>UIImgDefaultJacketUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultPantsUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultShirtUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultShoesUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultSkirtUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultSocksUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultAlphaUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UIImgDefaultUnderwearUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>StartUpChannelUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>B56AF90D-6684-48E4-B1E4-722D3DEB2CB6</string>
- </map>
- <key>NearByChatChannelUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>E1158BD6-661C-4981-9DAD-4DCBFF062502</string>
- </map>
- <key>NotificationChannelUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>AEED3193-8709-4693-8558-7452CCA97AE5</string>
- </map>
- <key>AlertChannelUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>F3E07BC8-A973-476D-8C7F-F3B7293975D1</string>
- </map>
- <key>UIImgWhiteUUID</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
- </map>
- <key>UILineEditorCursorThickness</key>
- <map>
- <key>Comment</key>
- <string>UI Line Editor Cursor Thickness</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>UIMaxComboWidth</key>
- <map>
- <key>Comment</key>
- <string>Maximum width of combo box</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>500</real>
- </map>
- <key>UIMinimizedWidth</key>
- <map>
- <key>Comment</key>
- <string>Size of UI floater minimized width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>160</real>
- </map>
- <key>UIMultiSliderctrlSpacing</key>
- <map>
- <key>Comment</key>
- <string>UI multi slider ctrl spacing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>4</real>
- </map>
- <key>UIMultiTrackHeight</key>
- <map>
- <key>Comment</key>
- <string>UI multi track height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>6</real>
- </map>
- <key>UIPreeditMarkerBrightness</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Marker Brightness</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.4</real>
- </map>
- <key>UIPreeditMarkerGap</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Marker Gap</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>1</real>
- </map>
- <key>UIPreeditMarkerPosition</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Marker Position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>UIPreeditMarkerThickness</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Marker Thickness</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>1</real>
- </map>
- <key>UIPreeditStandoutBrightness</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Standout Brightness</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.6</real>
- </map>
- <key>UIPreeditStandoutGap</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Standout Gap</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>1</real>
- </map>
- <key>UIPreeditStandoutPosition</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Standout Position</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>UIPreeditStandoutThickness</key>
- <map>
- <key>Comment</key>
- <string>UI Preedit Standout Thickness</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>UIResizeBarHeight</key>
- <map>
- <key>Comment</key>
- <string>Size of UI resize bar height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>3</real>
- </map>
- <key>UIResizeBarOverlap</key>
- <map>
- <key>Comment</key>
- <string>Size of UI resize bar overlap</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>1</real>
- </map>
- <key>UIScaleFactor</key>
- <map>
- <key>Comment</key>
- <string>Size of UI relative to default layout on 1024x768 screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1.0</real>
- </map>
- <key>UIScrollbarSize</key>
- <map>
- <key>Comment</key>
- <string>UI scrollbar size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>15</real>
- </map>
- <key>UISliderctrlHeight</key>
- <map>
- <key>Comment</key>
- <string>UI slider ctrl height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>16</real>
- </map>
- <key>UISliderctrlSpacing</key>
- <map>
- <key>Comment</key>
- <string>UI slider ctrl spacing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>4</real>
- </map>
- <key>UISndAlert</key>
- <map>
- <key>Comment</key>
- <string>Sound file for alerts (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>ed124764-705d-d497-167a-182cd9fa2e6c</string>
- </map>
- <key>UISndBadKeystroke</key>
- <map>
- <key>Comment</key>
- <string>Sound file for invalid keystroke (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>2ca849ba-2885-4bc3-90ef-d4987a5b983a</string>
- </map>
- <key>UISndClick</key>
- <map>
- <key>Comment</key>
- <string>Sound file for mouse click (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6</string>
- </map>
- <key>UISndClickRelease</key>
- <map>
- <key>Comment</key>
- <string>Sound file for mouse button release (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6</string>
- </map>
- <key>UISndDebugSpamToggle</key>
- <map>
- <key>Comment</key>
- <string>Log UI sound effects as they are played</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UISndHealthReductionF</key>
- <map>
- <key>Comment</key>
- <string>Sound file for female pain (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>219c5d93-6c09-31c5-fb3f-c5fe7495c115</string>
- </map>
- <key>UISndHealthReductionM</key>
- <map>
- <key>Comment</key>
- <string>Sound file for male pain (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>e057c244-5768-1056-c37e-1537454eeb62</string>
- </map>
- <key>UISndHealthReductionThreshold</key>
- <map>
- <key>Comment</key>
- <string>Amount of health reduction required to trigger "pain" sound</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>UISndInvalidOp</key>
- <map>
- <key>Comment</key>
- <string>Sound file for invalid operations (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>4174f859-0d3d-c517-c424-72923dc21f65</string>
- </map>
- <key>UISndMoneyChangeDown</key>
- <map>
- <key>Comment</key>
- <string>Sound file for L$ balance increase (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>104974e3-dfda-428b-99ee-b0d4e748d3a3</string>
- </map>
- <key>UISndMoneyChangeThreshold</key>
- <map>
- <key>Comment</key>
- <string>Amount of change in L$ balance required to trigger "money" sound</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>50.0</real>
- </map>
- <key>UISndMoneyChangeUp</key>
- <map>
- <key>Comment</key>
- <string>Sound file for L$ balance decrease(uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>77a018af-098e-c037-51a6-178f05877c6f</string>
- </map>
- <key>UISndNewIncomingIMSession</key>
- <map>
- <key>Comment</key>
- <string>Sound file for new instant message session(uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>67cc2844-00f3-2b3c-b991-6418d01e1bb7</string>
- </map>
- <key>UISndObjectCreate</key>
- <map>
- <key>Comment</key>
- <string>Sound file for object creation (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>f4a0660f-5446-dea2-80b7-6482a082803c</string>
- </map>
- <key>UISndObjectDelete</key>
- <map>
- <key>Comment</key>
- <string>Sound file for object deletion (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>0cb7b00a-4c10-6948-84de-a93c09af2ba9</string>
- </map>
- <key>UISndObjectRezIn</key>
- <map>
- <key>Comment</key>
- <string>Sound file for rezzing objects (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>3c8fc726-1fd6-862d-fa01-16c5b2568db6</string>
- </map>
- <key>UISndObjectRezOut</key>
- <map>
- <key>Comment</key>
- <string>Sound file for derezzing objects (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>00000000-0000-0000-0000-000000000000</string>
- </map>
- <key>UISndSnapshot</key>
- <map>
- <key>Comment</key>
- <string>Sound file for taking a snapshot (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>3d09f582-3851-c0e0-f5ba-277ac5c73fb4</string>
- </map>
- <key>UISndStartIM</key>
- <map>
- <key>Comment</key>
- <string>Sound file for starting a new IM session (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>c825dfbc-9827-7e02-6507-3713d18916c1</string>
- </map>
- <key>UISndTeleportOut</key>
- <map>
- <key>Comment</key>
- <string>Sound file for teleporting (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>d7a9a565-a013-2a69-797d-5332baa1a947</string>
- </map>
- <key>UISndTyping</key>
- <map>
- <key>Comment</key>
- <string>Sound file for starting to type a chat message (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>5e191c7b-8996-9ced-a177-b2ac32bfea06</string>
- </map>
- <key>UISndWindowClose</key>
- <map>
- <key>Comment</key>
- <string>Sound file for closing a window (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>2c346eda-b60c-ab33-1119-b8941916a499</string>
- </map>
- <key>UISndWindowOpen</key>
- <map>
- <key>Comment</key>
- <string>Sound file for opening a window (uuid for sound asset)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>c80260ba-41fd-8a46-768a-6bf236360e3a</string>
- </map>
- <key>UISpinctrlBtnHeight</key>
- <map>
- <key>Comment</key>
- <string>UI spin control button height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>11</integer>
- </map>
- <key>UISpinctrlBtnWidth</key>
- <map>
- <key>Comment</key>
- <string>UI spin control button width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>16</integer>
- </map>
- <key>UISpinctrlDefaultLabelWidth</key>
- <map>
- <key>Comment</key>
- <string>UI spin control default label width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>UISpinctrlSpacing</key>
- <map>
- <key>Comment</key>
- <string>UI spin control spacing</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
- <key>UITabCntrArrowBtnSize</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Arrow Button Size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>16</integer>
- </map>
- <key>UITabCntrvArrowBtnSize</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container V Arrow Button Size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>16</integer>
- </map>
- <key>UITabCntrvPad</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container V Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UITabCntrButtonPanelOverlap</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Button Panel Overlap</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UITabCntrCloseBtnSize</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Close Button Size</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>16</integer>
- </map>
- <key>UITabCntrTabHPad</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Tab Horizontal Pad</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>4</integer>
- </map>
- <key>UITabCntrTabPartialWidth</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Tab Partial Width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>12</integer>
- </map>
- <key>UITabCntrVertTabMinWidth</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Container Vertical Tab Minimum Width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>100</integer>
- </map>
- <key>UITabPadding</key>
- <map>
- <key>Comment</key>
- <string>UI Tab Padding</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>15</integer>
- </map>
- <key>UpdaterServiceSetting</key>
- <map>
- <key>Comment</key>
- <string>Configure updater service.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>UpdaterServiceCheckPeriod</key>
- <map>
- <key>Comment</key>
- <string>Default period between update checking.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>3600</integer>
- </map>
- <key>UpdaterServiceURL</key>
- <map>
- <key>Comment</key>
- <string>Default location for the updater service.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>https://update.secondlife.com</string>
- </map>
- <key>UpdaterServicePath</key>
- <map>
- <key>Comment</key>
- <string>Path on the update server host.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>update</string>
- </map>
- <key>UpdaterServiceProtocolVersion</key>
- <map>
- <key>Comment</key>
- <string>The update protocol version to use.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>v1.0</string>
- </map>
- <key>UploadBakedTexOld</key>
- <map>
- <key>Comment</key>
- <string>Forces the baked texture pipeline to upload using the old method.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseAltKeyForMenus</key>
- <map>
- <key>Comment</key>
- <string>Access menus via keyboard by tapping Alt</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseChatBubbles</key>
- <map>
- <key>Comment</key>
- <string>Show chat above avatars head in chat bubbles</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseCircuitCodeMaxRetries</key>
- <map>
- <key>Comment</key>
- <string>Max timeout count for the initial UseCircuitCode message</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <real>3</real>
- </map>
- <key>UseCircuitCodeTimeout</key>
- <map>
- <key>Comment</key>
- <string>Timeout duration in seconds for the initial UseCircuitCode message</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>UseDebugLogin</key>
- <map>
- <key>Comment</key>
- <string>Provides extra control over which grid to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseDebugMenus</key>
- <map>
- <key>Comment</key>
- <string>Turns on "Debug" menu</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseDefaultColorPicker</key>
- <map>
- <key>Comment</key>
- <string>Use color picker supplied by operating system</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseDisplayNames</key>
- <map>
- <key>Comment</key>
- <string>Use new, changeable, unicode names</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseEnergy</key>
- <map>
- <key>Comment</key>
- <string />
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseExternalBrowser</key>
- <map>
- <key>Comment</key>
- <string>Use default browser when opening web pages instead of in-world browser.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseFreezeFrame</key>
- <map>
- <key>Comment</key>
- <string>Freeze time when taking snapshots.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UseOcclusion</key>
- <map>
- <key>Comment</key>
- <string>Enable object culling based on occlusion (coverage) by other objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>RenderDelayVBUpdate</key>
- <map>
- <key>Comment</key>
- <string>Delay vertex buffer updates until just before rendering</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SpeakerParticipantDefaultOrder</key>
- <map>
- <key>Comment</key>
- <string>Order for displaying speakers in voice controls. 0 = alphabetical. 1 = recent.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>SpeakerParticipantRemoveDelay</key>
- <map>
- <key>Comment</key>
- <string>Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>UseNewWalkRun</key>
- <map>
- <key>Comment</key>
- <string>Replace standard walk/run animations with new ones.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseStartScreen</key>
- <map>
- <key>Comment</key>
- <string>Whether to load a start screen image or not.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseWebPagesOnPrims</key>
- <map>
- <key>Comment</key>
- <string>[NOT USED]</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UserConnectionPort</key>
- <map>
- <key>Comment</key>
- <string>Port that this client transmits on.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>UserLogFile</key>
- <map>
- <key>Comment</key>
- <string>User specified log file name.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>UserLoginInfo</key>
- <map>
- <key>Comment</key>
- <string>Users loging data.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>LLSD</string>
- <key>Value</key>
- </map>
- <key>VFSOldSize</key>
- <map>
- <key>Comment</key>
- <string>[DO NOT MODIFY] Controls resizing of local file cache</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VFSSalt</key>
- <map>
- <key>Comment</key>
- <string>[DO NOT MODIFY] Controls local file caching behavior</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VectorizeEnable</key>
- <map>
- <key>Comment</key>
- <string>Enable general vector operations and data alignment.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VectorizePerfTest</key>
- <map>
- <key>Comment</key>
- <string>Test SSE/vectorization performance and choose fastest version.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VectorizeProcessor</key>
- <map>
- <key>Comment</key>
- <string>0=Compiler Default, 1=SSE, 2=SSE2, autodetected</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VectorizeSkin</key>
- <map>
- <key>Comment</key>
- <string>Enable vector operations for avatar skinning.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VelocityInterpolate</key>
- <map>
- <key>Comment</key>
- <string>Extrapolate object motion from last packet based on received velocity</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>InterpolationTime</key>
- <map>
- <key>Comment</key>
- <string>How long to extrapolate object motion after last packet received</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>InterpolationPhaseOut</key>
- <map>
- <key>Comment</key>
- <string>Seconds to phase out interpolated motion</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VerboseLogs</key>
- <map>
- <key>Comment</key>
- <string>Display source file and line number for each log item for debugging purposes</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VertexShaderEnable</key>
- <map>
- <key>Comment</key>
- <string>Enable/disable all GLSL shaders (debug)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VivoxAutoPostCrashDumps</key>
- <map>
- <key>Comment</key>
- <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VivoxDebugLevel</key>
- <map>
- <key>Comment</key>
- <string>Logging level to use when launching the vivox daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>-1</string>
- </map>
- <key>VivoxDebugSIPURIHostName</key>
- <map>
- <key>Comment</key>
- <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxDebugVoiceAccountServerURI</key>
- <map>
- <key>Comment</key>
- <string>URI to the vivox account management server (empty string for the default).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VivoxVoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
- <key>VivoxVoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
- <key>VoiceCallsFriendsOnly</key>
- <map>
- <key>Comment</key>
- <string>Only accept voice calls from residents on your friends list</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceCallsRejectAll</key>
- <map>
- <key>Comment</key>
- <string>Silently reject all incoming voice calls.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceDisableMic</key>
- <map>
- <key>Comment</key>
- <string>Completely disable the ability to open the mic.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceEffectExpiryWarningTime</key>
- <map>
- <key>Comment</key>
- <string>How much notice to give of Voice Morph subscriptions expiry, in seconds.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>259200</integer>
- </map>
- <key>VoiceMorphingEnabled</key>
- <map>
- <key>Comment</key>
- <string>Whether or not to enable Voice Morphs and show the UI.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>AutoDisengageMic</key>
- <map>
- <key>Comment</key>
- <string>Automatically turn off the microphone when ending IM calls.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>VoiceEarLocation</key>
- <map>
- <key>Comment</key>
- <string>Location of the virtual ear for voice</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceHost</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice host to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>127.0.0.1</string>
- </map>
- <key>VoiceImageLevel0</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 0</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>041ee5a0-cb6a-9ac5-6e49-41e9320507d5</string>
- </map>
- <key>VoiceImageLevel1</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 1</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceImageLevel2</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 2</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceImageLevel3</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 3</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceImageLevel4</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 4</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceImageLevel5</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 5</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceImageLevel6</key>
- <map>
- <key>Comment</key>
- <string>Texture UUID for voice image level 6</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
- </map>
- <key>VoiceInputAudioDevice</key>
- <map>
- <key>Comment</key>
- <string>Audio input device to use for voice</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Default</string>
- </map>
- <key>VoiceLogFile</key>
- <map>
- <key>Comment</key>
- <string>Log file to use when launching the voice daemon</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>VoiceOutputAudioDevice</key>
- <map>
- <key>Comment</key>
- <string>Audio output device to use for voice</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>Default</string>
- </map>
- <key>VoiceParticipantLeftRemoveDelay</key>
- <map>
- <key>Comment</key>
- <string>Timeout to remove participants who has left Voice chat from the list in Voice Controls Panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>VoicePort</key>
- <map>
- <key>Comment</key>
- <string>Client SLVoice port to connect to</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>44125</integer>
- </map>
- <key>WarningsAsChat</key>
- <map>
- <key>Comment</key>
- <string>Display warning messages in chat history</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>VoiceServerType</key>
- <map>
- <key>Comment</key>
- <string>The type of voice server to connect to.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>vivox</string>
- </map>
- <key>WLSkyDetail</key>
- <map>
- <key>Comment</key>
- <string>Controls vertex detail on the WindLight sky. Lower numbers will give better performance and uglier skies.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>64</integer>
- </map>
- <key>WatchdogEnabled</key>
- <map>
- <key>Comment</key>
- <string>Controls whether the thread watchdog timer is activated.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>WaterEditPresets</key>
- <map>
- <key>Comment</key>
- <string>Whether to be able to edit the water defaults or not</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>WaterGLFogDensityScale</key>
- <map>
- <key>Comment</key>
- <string>Maps shader water fog density to gl fog density</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.02</real>
- </map>
- <key>WaterGLFogDepthFloor</key>
- <map>
- <key>Comment</key>
- <string>Controls how dark water gl fog can get</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>WaterGLFogDepthScale</key>
- <map>
- <key>Comment</key>
- <string>Controls how quickly gl fog gets dark under water</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>50.0</real>
- </map>
- <key>WellIconFlashCount</key>
- <map>
- <key>Comment</key>
- <string>Number of flashes of IM Well and Notification Well icons after which flashing buttons stay lit up. Requires restart.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>3</integer>
- </map>
- <key>WellIconFlashPeriod</key>
- <map>
- <key>Comment</key>
- <string>Period at which IM Well and Notification Well icons flash (seconds). Requires restart.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.25</real>
- </map>
- <key>WindLightUseAtmosShaders</key>
- <map>
- <key>Comment</key>
- <string>Whether to enable or disable WindLight atmospheric shaders.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>WindowFullScreen</key>
- <map>
- <key>Comment</key>
- <string>SL viewer window full screen</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>WindowHeight</key>
- <map>
- <key>Comment</key>
- <string>SL viewer window height</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>738</integer>
- </map>
- <key>WindowMaximized</key>
- <map>
- <key>Comment</key>
- <string>SL viewer window maximized on login</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>WindowWidth</key>
- <map>
- <key>Comment</key>
- <string>SL viewer window width</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>1024</integer>
- </map>
- <key>WindowX</key>
- <map>
- <key>Comment</key>
- <string>X coordinate of lower left corner of SL viewer window, relative to primary display (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>WindowY</key>
- <map>
- <key>Comment</key>
- <string>Y coordinate of lower left corner of SL viewer window, relative to primary display (pixels)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>XferThrottle</key>
- <map>
- <key>Comment</key>
- <string>Maximum allowable downstream bandwidth for asset transfers (bits per second)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>150000.0</real>
- </map>
- <key>ExternalEditor</key>
- <map>
- <key>Comment</key>
- <string>Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s"</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>YawFromMousePosition</key>
- <map>
- <key>Comment</key>
- <string>Horizontal range over which avatar head tracks mouse position (degrees of head rotation from left of window to right)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>90.0</real>
- </map>
- <key>YouAreHereDistance</key>
- <map>
- <key>Comment</key>
- <string>Radius of distance for banner that indicates if the resident is "on" the Place.(meters from avatar to requested place)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>YieldTime</key>
- <map>
- <key>Comment</key>
- <string>Yield some time to the local host.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>-1</integer>
- </map>
- <key>ZoomDirect</key>
- <map>
- <key>Comment</key>
- <string>Map Joystick zoom axis directly to camera zoom.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ZoomTime</key>
- <map>
- <key>Comment</key>
- <string>Time of transition between different camera modes (seconds)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.40000000596</real>
- </map>
- <key>moapbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight media on a prim sources</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>particlesbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight particle generators</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>physicalbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight physical objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>renderbeacons</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight particle generators</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>renderhighlights</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight scripted objects with touch function</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>scriptsbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight scripted objects</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>scripttouchbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight scripted objects with touch function</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ShowDeviceSettings</key>
- <map>
- <key>Comment</key>
- <string>Show device settings</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>SLURLDragNDrop</key>
- <map>
- <key>Comment</key>
- <string>Enable drag and drop of SLURLs onto the viewer</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>soundsbeacon</key>
- <map>
- <key>Comment</key>
- <string>Beacon / Highlight sound generators</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LogTextureDownloadsToViewerLog</key>
- <map>
- <key>Comment</key>
- <string>Send texture download details to the viewer log</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>LogTextureDownloadsToSimulator</key>
- <map>
- <key>Comment</key>
- <string>Send a digest of texture info to the sim</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>TextureLoggingThreshold</key>
- <map>
- <key>Comment</key>
- <string>Specifies the byte threshold at which texture download data should be sent to the sim.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-
- <!-- Settings below are for back compatibility only.
- They are not used in current viewer anymore. But they can't be removed to avoid
- influence on previous versions of the viewer in case of settings are not used or default value
- should be changed. See also EXT-6661. -->
- <!-- 1.23 settings -->
- <key>ShowVoiceChannelPopup</key>
- <map>
- <key>Comment</key>
- <string>Controls visibility of the current voice channel popup above the voice tab</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowVolumeSettingsPopup</key>
- <map>
- <key>Comment</key>
- <string>Show individual volume slider for voice, sound effects, etc</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>max_texture_dimension_X</key>
- <map>
- <key>Comment</key>
- <string>Maximum texture width for user uploaded textures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2048</integer>
- </map>
- <key>max_texture_dimension_Y</key>
- <map>
- <key>Comment</key>
- <string>Maximum texture height for user uploaded textures</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2048</integer>
- </map>
- <!-- End of back compatibility settings -->
- <key>teleport_offer_invitation_max_length</key>
- <map>
- <key>Comment</key>
- <string>Maximum length of teleport offer invitation line editor. 254 - max_location_url_length(76) = 178</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>178</integer>
- </map>
- <key>always_showable_floaters</key>
- <map>
- <key>Comment</key>
- <string>Floaters that can be shown despite mouselook mode</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>LLSD</string>
- <key>Value</key>
- <array>
- <string>snapshot</string>
- <string>postcard</string>
- <string>mini_map</string>
- </array>
- </map>
- <key>LandmarksSortedByDate</key>
- <map>
- <key>Comment</key>
- <string>Reflects landmarks panel sorting order.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>OutfitOperationsTimeout</key>
- <map>
- <key>Comment</key>
- <string>Timeout for outfit related operations.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>180</integer>
- </map>
- <key>HeightUnits</key>
- <map>
- <key>Comment</key>
- <string>Determines which metric units are used: 1(TRUE) for meter and 0(FALSE) for foot.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>TipToastMessageLineCount</key>
- <map>
- <key>Comment</key>
- <string>Max line count of text message on tip toast.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>10</integer>
- </map>
- <key>NotMovingHintTimeout</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds to wait for resident to move before displaying move hint.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>120.0</real>
- </map>
- <key>DestinationGuideHintTimeout</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds to wait before telling resident about destination guide.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1200.0</real>
- </map>
- <key>SidePanelHintTimeout</key>
- <map>
- <key>Comment</key>
- <string>Number of seconds to wait before telling resident about side panel.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>300.0</real>
- </map>
- <key>GroupMembersSortOrder</key>
- <map>
- <key>Comment</key>
- <string>The order by which group members will be sorted (name|donated|online)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string>name</string>
- </map>
- <key>SessionSettingsFile</key>
- <map>
- <key>Comment</key>
- <string>Settings that are a applied per session (not saved).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string></string>
- </map>
- <key>UserSessionSettingsFile</key>
- <map>
- <key>Comment</key>
- <string>User settings that are a applied per session (not saved).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>String</string>
- <key>Value</key>
- <string />
- </map>
- <key>OpenSidePanelsInFloaters</key>
- <map>
- <key>Comment</key>
- <string>If true, will always open side panel contents in a floater.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>AvatarInspectorTooltipDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before displaying avatar inspector tooltip</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.35</real>
- </map>
- <key>ObjectInspectorTooltipDelay</key>
- <map>
- <key>Comment</key>
- <string>Seconds before displaying object inspector tooltip</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.35</real>
- </map>
- <key>SLURLTeleportDirectly</key>
- <map>
- <key>Comment</key>
- <string>Clicking on a slurl will teleport you directly instead of opening places panel</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>EnableClassifieds</key>
- <map>
- <key>Comment</key>
- <string>Enable creation of new classified ads from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableGroupInfo</key>
- <map>
- <key>Comment</key>
- <string>Enable viewing and editing of group info from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnablePicks</key>
- <map>
- <key>Comment</key>
- <string>Enable editing of picks from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableWorldMap</key>
- <map>
- <key>Comment</key>
- <string>Enable opening world map from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableAvatarPay</key>
- <map>
- <key>Comment</key>
- <string>Enable paying other avatars from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableVoiceCall</key>
- <map>
- <key>Comment</key>
- <string>Enable voice calls from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>EnableAvatarShare</key>
- <map>
- <key>Comment</key>
- <string>Enable sharing from web link</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>SearchFromAddressBar</key>
- <map>
- <key>Comment</key>
- <string>Can enter search queries into navigation address bar</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>LogInventoryDecline</key>
- <map>
- <key>Comment</key>
- <string>Log in system chat whenever an inventory offer is declined</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>UseHTTPInventory</key>
- <map>
- <key>Comment</key>
- <string>Allow use of http inventory transfers instead of UDP</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
- <key>ClickToWalk</key>
- <map>
- <key>Comment</key>
- <string>Click in world to walk to location</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
- <key>ShowOfferedInventory</key>
- <map>
- <key>Comment</key>
- <string>Show inventory window with last inventory offer selected when receiving inventory from other users.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>Boolean</string>
- <key>Value</key>
- <integer>1</integer>
- </map>
-</map>
-</llsd>
+<?xml version="1.0" ?>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="llsd.xsd">
+<map>
+ <key>CrashHostUrl</key>
+ <map>
+ <key>Comment</key>
+ <string>A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>AFKTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Time before automatically setting AFK (away from keyboard) mode (seconds, 0=never).
+ Valid values are: 0, 120, 300, 600, 1800</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>300</real>
+ </map>
+ <key>AdminMenu</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable the debug admin menu from the main menu. Note: This will just allow the menu to be shown; this does not grant admin privileges.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ActiveFloaterTransparency</key>
+ <map>
+ <key>Comment</key>
+ <string>Transparency of active floaters (floaters that have focus)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.95</real>
+ </map>
+ <key>AdvanceSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Display advanced parameter settings in snaphot interface</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AgentPause</key>
+ <map>
+ <key>Comment</key>
+ <string>Ask the simulator to stop updating the agent while enabled</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AlertedUnsupportedHardware</key>
+ <map>
+ <key>Comment</key>
+ <string>Set if there's unsupported hardware and we've already done a notification.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AllowMultipleViewers</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow multiple viewers.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AllowTapTapHoldRun</key>
+ <map>
+ <key>Comment</key>
+ <string>Tapping a direction key twice and holding it down makes avatar run</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AnimateTextures</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable texture animation (debug)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AnimationDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Show active animations in a bubble above avatars head</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AppearanceCameraMovement</key>
+ <map>
+ <key>Comment</key>
+ <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ApplyColorImmediately</key>
+ <map>
+ <key>Comment</key>
+ <string>Preview selections in color picker immediately</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ApplyTextureImmediately</key>
+ <map>
+ <key>Comment</key>
+ <string>Preview selections in texture picker immediately</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ArrowKeysAlwaysMove</key>
+ <map>
+ <key>Comment</key>
+ <string>While cursor is in chat entry box, arrow keys still control your avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AskedAboutCrashReports</key>
+ <map>
+ <key>Comment</key>
+ <string>Turns off dialog asking if you want to enable crash reporting</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AuctionShowFence</key>
+ <map>
+ <key>Comment</key>
+ <string>When auctioning land, include parcel boundary marker in snapshot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AudioLevelAmbient</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of environment sounds</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelDoppler</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of doppler effect on moving audio sources (1.0 = normal, &lt;1.0 = diminished doppler effect, &gt;1.0 = enhanced doppler effect)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AudioLevelMaster</key>
+ <map>
+ <key>Comment</key>
+ <string>Master audio level, or overall volume</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AudioLevelMedia</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of Quicktime movies</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelMic</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of microphone input</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AudioLevelMusic</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of streaming music</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelRolloff</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AudioLevelSFX</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of in-world sound effects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelUI</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of UI sound effects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of voice chat</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioLevelWind</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio level of wind noise when standing still</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>AudioStreamingMedia</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable streaming</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AudioStreamingMusic</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable streaming audio</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AuditTexture</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable texture auditting.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoAcceptNewInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically accept new notecards/textures/landmarks</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoLeveling</key>
+ <map>
+ <key>Comment</key>
+ <string>Keep Flycam level.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AutoLoadWebProfiles</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically load ALL profile webpages without asking first.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoLogin</key>
+ <map>
+ <key>Comment</key>
+ <string>Login automatically using last username/password combination</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoMimeDiscovery</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewer mime type discovery of media URLs</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoPilotLocksCamera</key>
+ <map>
+ <key>Comment</key>
+ <string>Keep camera position locked when avatar walks to selected position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutoSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Update snapshot when camera stops moving, or any parameter changes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AutomaticFly</key>
+ <map>
+ <key>Comment</key>
+ <string>Fly by holding jump key or using "Fly" command (FALSE = fly by using "Fly" command only)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvalinePhoneSeparator</key>
+ <map>
+ <key>Comment</key>
+ <string>Separator of phone parts to have Avaline numbers human readable in Voice Control Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>-</string>
+ </map>
+ <key>AvatarAxisDeadZone0</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 0 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisDeadZone1</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 1 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisDeadZone2</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 2 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisDeadZone3</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 3 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisDeadZone4</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 4 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisDeadZone5</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 5 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AvatarAxisScale0</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 0 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarAxisScale1</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 1 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarAxisScale2</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 2 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarAxisScale3</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 3 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarAxisScale4</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 4 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarAxisScale5</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar axis 5 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>AvatarBacklight</key>
+ <map>
+ <key>Comment</key>
+ <string>Add rim lighting to avatar rendering to approximate shininess of skin</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvatarFeathering</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar feathering (less is softer)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16.0</real>
+ </map>
+ <key>AvatarPickerSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>AvatarPickerURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar picker contents</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>AvatarBakedTextureUploadTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>60</integer>
+ </map>
+ <key>AvatarBakedLocalTextureUpdateTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifes the maximum time in seconds to wait before updating your appearance during appearance mode.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>AvatarPhysics</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable avatar physics.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvatarPhysicsTest</key>
+ <map>
+ <key>Comment</key>
+ <string>Simulate continuous physics behavior on all nearby avatars.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AvatarSex</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>BackgroundYieldTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of time to yield every frame to other applications when SL is not the foreground window (milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>40</integer>
+ </map>
+ <key>BottomPanelNew</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable the new bottom panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BrowserHomePage</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://www.secondlife.com</string>
+ </map>
+ <key>BrowserIgnoreSSLCertErrors</key>
+ <map>
+ <key>Comment</key>
+ <string>FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BlockAvatarAppearanceMessages</key>
+ <map>
+ <key>Comment</key>
+ <string>Ignores appearance messages (for simulating Ruth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BlockSomeAvatarAppearanceVisualParams</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BrowserProxyAddress</key>
+ <map>
+ <key>Comment</key>
+ <string>Address for the Web Proxy]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>BrowserProxyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Web Proxy</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BrowserProxyExclusions</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>BrowserProxyPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Port for Web Proxy</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3128</integer>
+ </map>
+ <key>BrowserProxySocks45</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>BuildAxisDeadZone0</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 0 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisDeadZone1</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 1 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisDeadZone2</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 2 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisDeadZone3</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 3 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisDeadZone4</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 4 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisDeadZone5</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 5 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>BuildAxisScale0</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 0 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildAxisScale1</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 1 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildAxisScale2</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 2 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildAxisScale3</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 3 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildAxisScale4</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 4 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildAxisScale5</key>
+ <map>
+ <key>Comment</key>
+ <string>Build axis 5 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>BuildFeathering</key>
+ <map>
+ <key>Comment</key>
+ <string>Build feathering (less is softer)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16.0</real>
+ </map>
+ <key>BulkChangeIncludeAnimations</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect animations</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeBodyParts</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect body parts</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeClothing</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect clothing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeGestures</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect gestures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeNotecards</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect notecards</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeScripts</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect scripts</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeSounds</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect sounds</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeIncludeTextures</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk permission changes affect textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BulkChangeEveryoneCopy</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk changed objects can be copied by everyone</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BulkChangeNextOwnerCopy</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk changed objects can be copied by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BulkChangeNextOwnerModify</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk changed objects can be modified by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BulkChangeNextOwnerTransfer</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk changed objects can be resold or given away by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>BulkChangeShareWithGroup</key>
+ <map>
+ <key>Comment</key>
+ <string>Bulk changed objects are shared with the currently active group</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ButtonFlashCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of flashes after which flashing buttons stay lit up</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>8</integer>
+ </map>
+ <key>ButtonFlashRate</key>
+ <map>
+ <key>Comment</key>
+ <string>Frequency at which buttons flash (hz)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.25</real>
+ </map>
+ <key>ButtonHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>Default horizontal spacing between buttons (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>ButtonHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Default height for normal buttons (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>23</integer>
+ </map>
+ <key>ButtonHeightSmall</key>
+ <map>
+ <key>Comment</key>
+ <string>Default height for small buttons (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>23</integer>
+ </map>
+ <key>CacheLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls the location of the local disk cache</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>CacheLocationTopFolder</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls the top folder location of the the local disk cache</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>CacheNumberOfRegionsForObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls number of regions to be cached for objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>128</integer>
+ </map>
+ <key>CacheSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls amount of hard drive space reserved for local file caching in MB</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>512</integer>
+ </map>
+ <key>CacheValidateCounter</key>
+ <map>
+ <key>Comment</key>
+ <string>Used to distribute cache validation</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CameraMouseWheelZoom</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera zooms in and out with mousewheel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>CameraAngle</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera field of view angle (Radians)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.047197551</real>
+ </map>
+ <key>CameraOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Render with camera offset from view frustum (rendering debug)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CameraOffsetBuild</key>
+ <map>
+ <key>Comment</key>
+ <string>Default camera position relative to focus point when entering build mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>-6.0</real>
+ <real>0.0</real>
+ <real>6.0</real>
+ </array>
+ </map>
+ <key>CameraOffsetRearView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial camera offset from avatar in Rear View</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>-3.0</real>
+ <real>0.0</real>
+ <real>0.75</real>
+ </array>
+ </map>
+ <key>CameraOffsetFrontView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial camera offset from avatar in Front View</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>2.2</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ </map>
+ <key>CameraOffsetGroupView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial camera offset from avatar in Group View</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>-1.0</real>
+ <real>0.7</real>
+ <real>0.5</real>
+ </array>
+ </map>
+ <key>CameraOffsetScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scales the default offset</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>CameraPosOnLogout</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera position when last logged out (global coordinates)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3D</string>
+ <key>Value</key>
+ <array>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ </map>
+ <key>CameraPositionSmoothing</key>
+ <map>
+ <key>Comment</key>
+ <string>Smooths camera position over time</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>CameraPreset</key>
+ <map>
+ <key>Comment</key>
+ <string>Preset camera position - view (0 - rear, 1 - front, 2 - group)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>CameraFocusTransitionTime</key>
+ <map>
+ <key>Comment</key>
+ <string>How many seconds it takes the camera to transition between focal distances</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+
+ <key>CameraFNumber</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera f-number value for DoF effect</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>9.0</real>
+ </map>
+
+ <key>CameraFocalLength</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera focal length for DoF effect (in millimeters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>50</real>
+ </map>
+
+ <key>CameraFieldOfView</key>
+ <map>
+ <key>Comment</key>
+ <string>Vertical camera field of view for DoF effect (in degrees)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>60.0</real>
+ </map>
+
+ <key>CameraAspectRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera aspect ratio for DoF effect</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.5</real>
+ </map>
+
+ <key>CertStore</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies the Certificate Store for certificate trust verification</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
+ <key>ChatBarStealsFocus</key>
+ <map>
+ <key>Comment</key>
+ <string>Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LetterKeysFocusChatBar</key>
+ <map>
+ <key>Comment</key>
+ <string>When printable characters keys (possibly with Shift held) are pressed, the chatbar takes focus</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ChatBubbleOpacity</key>
+ <map>
+ <key>Comment</key>
+ <string>Opacity of chat bubble background (0.0 = completely transparent, 1.0 = completely opaque)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>ChatFontSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of chat text in chat console (0 = small, 1 = big)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatFullWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Chat console takes up full width of SL window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatHistoryTornOff</key>
+ <map>
+ <key>Comment</key>
+ <string>Show chat history window separately from Communicate window.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ChatOnlineNotification</key>
+ <map>
+ <key>Comment</key>
+ <string>Provide notifications for when friend log on and off of SL</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatPersistTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Time for which chat stays visible in console (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>20.0</real>
+ </map>
+ <key>ChatShowTimestamps</key>
+ <map>
+ <key>Comment</key>
+ <string>Show timestamps in chat</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatVisible</key>
+ <map>
+ <key>Comment</key>
+ <string>Chat bar is visible</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatWindow</key>
+ <map>
+ <key>Comment</key>
+ <string>Show chat in multiple windows(by default) or in one multi-tabbed window(requires restart)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CheesyBeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable cheesy beacon effects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ClientSettingsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Client settings file name (per install).</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>CloseChatOnReturn</key>
+ <map>
+ <key>Comment</key>
+ <string>Close chat after hitting return</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CloseSnapshotOnKeep</key>
+ <map>
+ <key>Comment</key>
+ <string>Close snapshot window after saving snapshot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>CmdLineDisableVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable Voice.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CmdLineGridChoice</key>
+ <map>
+ <key>Comment</key>
+ <string>The user's grid choice or ip address.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>CmdLineHelperURI</key>
+ <map>
+ <key>Comment</key>
+ <string>Command line specified helper web CGI prefix to use.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>CmdLineLoginURI</key>
+ <map>
+ <key>Comment</key>
+ <string>Command line specified login server and CGI prefix to use.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string />
+ </array>
+ </map>
+ <key>CompressSnapshotsToDisk</key>
+ <map>
+ <key>Comment</key>
+ <string>Compress snapshots saved to disk (Using JPEG 2000)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ConnectAsGod</key>
+ <map>
+ <key>Comment</key>
+ <string>Log in a god if you have god access.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ConnectionPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Custom connection port number</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>13000</integer>
+ </map>
+ <key>ConnectionPortEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Use the custom connection port?</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ConsoleBackgroundOpacity</key>
+ <map>
+ <key>Comment</key>
+ <string>Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.700</real>
+ </map>
+ <key>ConsoleBufferSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of chat console history (lines of chat)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>40</integer>
+ </map>
+ <key>ConsoleMaxLines</key>
+ <map>
+ <key>Comment</key>
+ <string>Max number of lines of chat text visible in console.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>40</integer>
+ </map>
+ <key>ContactsTornOff</key>
+ <map>
+ <key>Comment</key>
+ <string>Show contacts window separately from Communicate window.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CookiesEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Accept cookies from Web sites?</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BrowserJavascriptEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Javascript in the built-in Web browser?</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>BrowserPluginsEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Web plugins in the built-in Web browser?</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ChatBarCustomWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Stores customized width of chat bar.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CreateToolCopyCenters</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>CreateToolCopyRotates</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CreateToolCopySelection</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>CreateToolKeepSelected</key>
+ <map>
+ <key>Comment</key>
+ <string>After using create tool, keep the create tool active</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>Cursor3D</key>
+ <map>
+ <key>Comment</key>
+ <string>Treat Joystick values as absolute positions (not deltas).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>CurrentGrid</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently Selected Grid</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>CustomServer</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies IP address or hostname of grid to which you connect</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>DebugAvatarRezTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Display times for avatars to resolve.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugAvatarLocalTexLoadedTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Display time for loading avatar local textures.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugBeaconLineWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of lines for Debug Beacons</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DebugInventoryFilters</key>
+ <map>
+ <key>Comment</key>
+ <string>Turn on debugging display for inventory filtering</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugPermissions</key>
+ <map>
+ <key>Comment</key>
+ <string>Log permissions for selected inventory items</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugPluginDisableTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable the code which watches for plugins that are crashed or hung</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Show color under cursor</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowMemory</key>
+ <map>
+ <key>Comment</key>
+ <string>Show Total Allocated Memory</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowRenderInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Show stats about current scene</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowUploadCost</key>
+ <map>
+ <key>Comment</key>
+ <string>Show what it would cost to upload assets in current scene</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowRenderMatrices</key>
+ <map>
+ <key>Comment</key>
+ <string>Display values of current view and projection matrices.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowTextureInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Show inertested texture info</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Show time info</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugShowXUINames</key>
+ <map>
+ <key>Comment</key>
+ <string>Show tooltips with XUI path to widget</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugStatModeFPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeBandwidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModePacketLoss</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatMode</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeKTrisDrawnFr</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeKTrisDrawnSec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeTotalObjs</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeNewObjs</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeTextureCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeRawCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeGLMem</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeFormattedMem</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeRawMem</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeBoundMem</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModePacketsIn</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModePacketsOut</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeTexture</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeAsset</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeLayers</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeActualIn</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeActualOut</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeVFSPendingOps</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeTimeDialation</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimFPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModePhysicsFPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModePinnedObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeLowLODObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeMemoryAllocated</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeAgentUpdatesSec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeMainAgents</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeChildAgents</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimActiveObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimActiveScripts</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimScriptEvents</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimInPPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimOutPPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimPendingDownloads</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>SimPendingUploads</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimTotalUnackedBytes</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimFrameMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimNetMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSimPhysicsMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSimOtherMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimAgentMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimImagesMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimScriptMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSpareMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSimPhysicsStepMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSimPhysicsShapeUpdateMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSimPhysicsOtherMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimSleepMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugStatModeSimPumpIOMsec</key>
+ <map>
+ <key>Comment</key>
+ <string>Mode of stat in Statistics floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>DebugViews</key>
+ <map>
+ <key>Comment</key>
+ <string>Display debugging info for views.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DebugWindowProc</key>
+ <map>
+ <key>Comment</key>
+ <string>Log windows messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DefaultFemaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Female Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Female Shape &amp; Outfit</string>
+ </map>
+ <key>DefaultMaleAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Default Male Avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Male Shape &amp; Outfit</string>
+ </map>
+
+ <key>DefaultObjectTexture</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture used as 'Default' in texture picker. (UUID texture reference)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>89556747-24cb-43ed-920b-47caed15465f</string>
+ </map>
+ <key>DefaultUploadCost</key>
+ <map>
+ <key>Comment</key>
+ <string>Default sound/image/file upload cost(in case economy data is not available).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>DestinationGuideURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Destination guide contents</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>DisableCameraConstraints</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable the normal bounds put on the camera by avatar position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DisableMouseWarp</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable warping of the mouse to the center of the screen during alt-zoom and mouse look. Useful with certain input devices, mouse sharing programs like Synergy, or running under Parallels.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DisableExternalBrowser</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable opening an external browser.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HeadlessClient</key>
+ <map>
+ <key>Comment</key>
+ <string>Run in headless mode by disabling GL rendering, keyboard, etc</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DisableTextHyperlinkActions</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable highlighting and linking of URLs in XUI text boxes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DisableVerticalSync</key>
+ <map>
+ <key>Comment</key>
+ <string>Update frames as fast as possible (FALSE = update frames between display scans)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableGroupChatPopups</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Incoming Group Chat Popups</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableIMChatPopups</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Incoming IM Chat Popups</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayAvatarAgentTarget</key>
+ <map>
+ <key>Comment</key>
+ <string>Show avatar positioning locators (animation debug)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DisplayChat</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Latest Chat message on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Network Information on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayDebugConsole</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Console Debug Information on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayIM</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Latest IM message on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayLinden</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Account Information on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayRegion</key>
+ <map>
+ <key>Comment</key>
+ <string>Display Location information on LCD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DisplayTimecode</key>
+ <map>
+ <key>Comment</key>
+ <string>Display timecode on screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>Disregard128DefaultDrawDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use the auto default to 128 draw distance</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>Disregard96DefaultDrawDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use the auto default to 96 draw distance</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ClickActionBuyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to buy actions in tool pie menu</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ClickActionPayEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to pay actions in tool pie menu</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DoubleClickAutoPilot</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable double-click auto pilot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DoubleClickTeleport</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable double-click to teleport where allowed</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DoubleClickShowWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable double-click to show world map from mini map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>DragAndDropToolTipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying tooltip when performing drag and drop operation</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.10000000149</real>
+ </map>
+ <key>DragAndDropDistanceThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of pixels that mouse should move before triggering drag and drop mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>DropShadowButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop shadow width for buttons (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>DropShadowFloater</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop shadow width for floaters (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>DropShadowSlider</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop shadow width for sliders (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>DropShadowTooltip</key>
+ <map>
+ <key>Comment</key>
+ <string>Drop shadow width for tooltips (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>DumpVFSCaches</key>
+ <map>
+ <key>Comment</key>
+ <string>Dump VFS caches on startup.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DynamicCameraStrength</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount camera lags behind avatar motion (0 = none, 30 = avatar velocity)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>2.0</real>
+ </map>
+ <key>EditCameraMovement</key>
+ <map>
+ <key>Comment</key>
+ <string>When entering build mode, camera moves up above avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EditLinkedParts</key>
+ <map>
+ <key>Comment</key>
+ <string>Select individual parts of linked objects</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EffectScriptChatParticles</key>
+ <map>
+ <key>Comment</key>
+ <string>1 = normal behavior, 0 = disable display of swirling lights when scripts communicate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableGrab</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Ctrl+mouse to grab and manipulate objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAltZoom</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Alt+mouse to look at and zoom in on objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableMouselook</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow first person perspective and mouse control of camera</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableRippleWater</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use ripple water shader or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableTextureAtlas</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use texture atlas or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableUIHints</key>
+ <map>
+ <key>Comment</key>
+ <string>Toggles UI hint popups</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableVoiceChat</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable talking to other residents with a microphone</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnergyFromTop</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>20</integer>
+ </map>
+ <key>EnergyHeight</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>40</integer>
+ </map>
+ <key>EnergyWidth</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>175</integer>
+ </map>
+ <key>EventURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for Event website, displayed in the event floater</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://events.secondlife.com/viewer/embed/event/</string>
+ </map>
+ <key>EveryoneCopy</key>
+ <map>
+ <key>Comment</key>
+ <string>Everyone can copy the newly created objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FeatureManagerHTTPTable</key>
+ <map>
+ <key>Comment</key>
+ <string>Base directory for HTTP feature/gpu table fetches</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://viewer-settings.secondlife.com</string>
+ </map>
+ <key>FPSLogFrequency</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds between display of FPS in log (0 for never)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>FilterItemsPerFrame</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>500</integer>
+ </map>
+ <key>FindLandArea</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables filtering of land search results by area</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FindLandPrice</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables filtering of land search results by price</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FindLandType</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale")</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>All</string>
+ </map>
+ <key>FindPeopleOnline</key>
+ <map>
+ <key>Comment</key>
+ <string>Limits people search to only users who are logged on</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FindPlacesPictures</key>
+ <map>
+ <key>Comment</key>
+ <string>Display only results of find places that have pictures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FirstLoginThisInstall</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies that you have not successfully logged in since you installed the latest update</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FirstName</key>
+ <map>
+ <key>Comment</key>
+ <string>Login first name</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>FirstPersonAvatarVisible</key>
+ <map>
+ <key>Comment</key>
+ <string>Display avatar and attachments below neck while in mouselook</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FirstRunThisInstall</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies that you have not run the viewer since you performed a clean install</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FirstLoginThisInstall</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies that you have not logged in with the viewer since you performed a clean install</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FirstSelectedDisabledPopups</key>
+ <map>
+ <key>Comment</key>
+ <string>Return false if there is not disabled popup selected in the list of floater preferences popups</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FirstSelectedEnabledPopups</key>
+ <map>
+ <key>Comment</key>
+ <string>Return false if there is not enable popup selected in the list of floater preferences popups</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FixedWeather</key>
+ <map>
+ <key>Comment</key>
+ <string>Weather effects do not change over time</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FloaterActiveSpeakersSortAscending</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to sort up or down</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FloaterActiveSpeakersSortColumn</key>
+ <map>
+ <key>Comment</key>
+ <string>Column name to sort on</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>speaking_status</string>
+ </map>
+ <key>FloaterMapNorth</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map North Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>N</string>
+ </map>
+ <key>FloaterMapNorthEast</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map North-East Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>NE</string>
+ </map>
+ <key>FloaterMapNorthWest</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map North-West Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>NW</string>
+ </map>
+ <key>FloaterMapEast</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map East Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>E</string>
+ </map>
+ <key>FloaterMapWest</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map West Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>W</string>
+ </map>
+ <key>FloaterMapSouth</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map South Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>S</string>
+ </map>
+ <key>FloaterMapSouthEast</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map South-East Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>SE</string>
+ </map>
+ <key>FloaterMapSouthWest</key>
+ <map>
+ <key>Comment</key>
+ <string>Floater Map South-West Label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>SW</string>
+ </map>
+
+ <key>FloaterStatisticsRect</key>
+ <map>
+ <key>Comment</key>
+ <string>Rectangle for chat history</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Rect</string>
+ <key>Value</key>
+ <array>
+ <integer>0</integer>
+ <integer>400</integer>
+ <integer>250</integer>
+ <integer>0</integer>
+ </array>
+ </map>
+ <key>FlycamAbsolute</key>
+ <map>
+ <key>Comment</key>
+ <string>Treat Flycam values as absolute positions (not deltas).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FlycamAxisDeadZone0</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 0 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone1</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 1 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone2</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 2 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone3</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 3 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone4</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 4 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone5</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 5 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisDeadZone6</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 6 dead zone.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>FlycamAxisScale0</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 0 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale1</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 1 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale2</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 2 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale3</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 3 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale4</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 4 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale5</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 5 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamAxisScale6</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam axis 6 scaler.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamBuildModeScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale factor to apply to flycam movements when in build mode.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>FlycamFeathering</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam feathering (less is softer)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16.0</real>
+ </map>
+ <key>FlycamZoomDirect</key>
+ <map>
+ <key>Comment</key>
+ <string>Map flycam zoom axis directly to camera zoom.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FlyingAtExit</key>
+ <map>
+ <key>Comment</key>
+ <string>Was flying when last logged out, so fly when logging in</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FocusOffsetRearView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3D</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+ <key>FocusOffsetFrontView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial focus point offset relative to avatar for the camera preset Front View</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3D</string>
+ <key>Value</key>
+ <array>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ </map>
+ <key>FocusOffsetGroupView</key>
+ <map>
+ <key>Comment</key>
+ <string>Initial focus point offset relative to avatar for the camera preset Group View</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3D</string>
+ <key>Value</key>
+ <array>
+ <real>1.5</real>
+ <real>0.7</real>
+ <real>1.0</real>
+ </array>
+ </map>
+ <key>FocusPosOnLogout</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera focus point when last logged out (global coordinates)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3D</string>
+ <key>Value</key>
+ <array>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ </map>
+ <key>FolderAutoOpenDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before automatically expanding the folder under the mouse when performing inventory drag and drop</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.75</real>
+ </map>
+ <key>FolderLoadingMessageWaitTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds to wait before showing the LOADING... text in folder views</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>FontScreenDPI</key>
+ <map>
+ <key>Comment</key>
+ <string>Font resolution, higher is bigger (pixels per inch)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>96.0</real>
+ </map>
+ <key>ForceAssetFail</key>
+ <map>
+ <key>Comment</key>
+ <string>Force wearable fetches to fail for this asset type.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>255</integer>
+ </map>
+ <key>ForceShowGrid</key>
+ <map>
+ <key>Comment</key>
+ <string>Always show grid dropdown on login screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ForceMandatoryUpdate</key>
+ <map>
+ <key>Comment</key>
+ <string>For QA: On next startup, forces the auto-updater to run</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FreezeTime</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FullScreenAspectRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Aspect ratio of fullscreen display (width / height)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>3</real>
+ </map>
+ <key>FullScreenAutoDetectAspectRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically detect proper aspect ratio for fullscreen display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GesturesMarketplaceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Gestures Marketplace</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://www.xstreetsl.com/modules.php?name=Marketplace&amp;CategoryID=233</string>
+ </map>
+ <key>GridCrossSections</key>
+ <map>
+ <key>Comment</key>
+ <string>Highlight cross sections of prims with grid manipulation plane.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GridDrawSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Visible extent of 2D snap grid (meters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>12.0</real>
+ </map>
+ <key>GridMode</key>
+ <map>
+ <key>Comment</key>
+ <string>Snap grid reference frame (0 = world, 1 = local, 2 = reference object)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GridOpacity</key>
+ <map>
+ <key>Comment</key>
+ <string>Grid line opacity (0.0 = completely transparent, 1.0 = completely opaque)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.699999988079</real>
+ </map>
+ <key>GridResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of single grid step (meters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>GridSubUnit</key>
+ <map>
+ <key>Comment</key>
+ <string>Display fractional grid steps, relative to grid size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GridSubdivision</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of times to divide single snap grid unit when GridSubUnit is true</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>32</integer>
+ </map>
+ <key>GroupNotifyBoxHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Height of group notice messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>260</integer>
+ </map>
+ <key>GroupNotifyBoxWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Width of group notice messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>305</integer>
+ </map>
+ <key>HelpUseLocal</key>
+ <map>
+ <key>Comment</key>
+ <string>If set, always use this for help: skins/default/html/[LANGUAGE]/help-offline/index.html</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HelpURLFormat</key>
+ <map>
+ <key>Comment</key>
+ <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://viewer-help.secondlife.com/[LANGUAGE]/[CHANNEL]/[VERSION]/[TOPIC][DEBUG_MODE]</string>
+ </map>
+ <key>HomeSidePanelURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for the web page to display in the Home side panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://viewer-sidebar.secondlife.com/sidebar.html?p=[AUTH_TOKEN]&amp;lang=[LANGUAGE]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]&amp;firstlogin=[FIRST_LOGIN]</string>
+ </map>
+ <key>SearchURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for Search website, displayed in the Find floater</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&amp;p=[AUTH_TOKEN]&amp;r=[MATURITY]&amp;lang=[LANGUAGE]&amp;g=[GODLIKE]&amp;sid=[SESSION_ID]&amp;rid=[REGION_ID]&amp;pid=[PARCEL_ID]&amp;channel=[CHANNEL]&amp;version=[VERSION]&amp;major=[VERSION_MAJOR]&amp;minor=[VERSION_MINOR]&amp;patch=[VERSION_PATCH]&amp;build=[VERSION_BUILD]</string>
+ </map>
+ <key>WebProfileURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for Web Profiles</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://my.secondlife.com/[AGENT_NAME]</string>
+ </map>
+ <key>WebProfileNonProductionURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for Web Profiles on Non-Production grids</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://my-demo.secondlife.com/[AGENT_NAME]</string>
+ </map>
+ <key>HighResSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Double resolution of snapshot from current window resolution</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HideSelectedObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Hide Selected Objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HostID</key>
+ <map>
+ <key>Comment</key>
+ <string>Machine identifier for hosted Second Life instances</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>HtmlHelpLastPage</key>
+ <map>
+ <key>Comment</key>
+ <string>Last URL visited via help system</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>IMShowTimestamps</key>
+ <map>
+ <key>Comment</key>
+ <string>Show timestamps in IM</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>IMShowControlPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Show IM Control Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>IgnoreAllNotifications</key>
+ <map>
+ <key>Comment</key>
+ <string>Ignore all notifications so we never need user input on them.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>IgnorePixelDepth</key>
+ <map>
+ <key>Comment</key>
+ <string>Ignore pixel depth settings.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ImagePipelineUseHTTP</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE use HTTP GET to fetch textures from the server</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InactiveFloaterTransparency</key>
+ <map>
+ <key>Comment</key>
+ <string>Transparency of inactive floaters (floaters that have no focus)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.65</real>
+ </map>
+ <key>InBandwidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Incoming bandwidth throttle (bps)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>InspectorFadeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Fade out timing for inspectors</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>InspectorShowTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Stay timing for inspectors</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>3.0</real>
+ </map>
+ <key>InstallLanguage</key>
+ <map>
+ <key>Comment</key>
+ <string>Language passed from installer (for UI)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
+ <key>InventoryAutoOpenDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before automatically opening inventory when mouse is over inventory button when performing inventory drag and drop</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>InventoryLinking</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable ability to create links to folders and items via "Paste as link".</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>InventorySortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>7</integer>
+ </map>
+ <key>InvertMouse</key>
+ <map>
+ <key>Comment</key>
+ <string>When in mouselook, moving mouse up looks down and vice verse (FALSE = moving up looks up)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>JoystickAvatarEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables the Joystick to control Avatar movement.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>JoystickAxis0</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 0 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>JoystickAxis1</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 1 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>JoystickAxis2</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 2 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>JoystickAxis3</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 3 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>JoystickAxis4</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 4 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>JoystickAxis5</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 5 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>JoystickAxis6</key>
+ <map>
+ <key>Comment</key>
+ <string>Flycam hardware axis mapping for internal axis 6 ([0, 5]).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>JoystickBuildEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables the Joystick to move edited objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>JoystickEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables Joystick Input.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>JoystickFlycamEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables the Joystick to control the flycam.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>JoystickInitialized</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not a joystick has been detected and initiailized.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>JoystickMouselookYaw</key>
+ <map>
+ <key>Comment</key>
+ <string>Pass joystick yaw to scripts in Mouselook.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>JoystickRunThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Input threshold to initiate running</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>KeepAspectForSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Use full window when taking snapshot, regardless of requested image size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LandBrushSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of affected region when using teraform tool</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>2.0</real>
+ </map>
+ <key>LCDDestination</key>
+ <map>
+ <key>Comment</key>
+ <string>Which LCD to use</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LSLFindCaseInsensitivity</key>
+ <map>
+ <key>Comment</key>
+ <string>Use case insensitivity when searching in LSL editor</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LSLHelpURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL that points to LSL help files, with [LSL_STRING] corresponding to the referenced LSL function or keyword</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://wiki.secondlife.com/wiki/[LSL_STRING]</string>
+ </map>
+ <key>LagMeterShrunk</key>
+ <map>
+ <key>Comment</key>
+ <string>Last large/small state for lag meter</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>Language</key>
+ <map>
+ <key>Comment</key>
+ <string>Language specifier (for UI)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
+ <key>LanguageIsPublic</key>
+ <map>
+ <key>Comment</key>
+ <string>Let other residents see our language information</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LastGPUClass</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] previous GPU class for tracking hardware changes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>LastFeatureVersion</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] Version number for tracking hardware changes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LastFindPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls which find operation appears by default when clicking "Find" button </string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>find_all_panel</string>
+ </map>
+ <key>LastName</key>
+ <map>
+ <key>Comment</key>
+ <string>Login last name</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>LastPrefTab</key>
+ <map>
+ <key>Comment</key>
+ <string>Last selected tab in preferences window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LastMediaSettingsTab</key>
+ <map>
+ <key>Comment</key>
+ <string>Last selected tab in media settings window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LastRunVersion</key>
+ <map>
+ <key>Comment</key>
+ <string>Version number of last instance of the viewer that you ran</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>0.0.0</string>
+ </map>
+
+ <key>LastSnapshotToEmailHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>The height of the last email snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>768</integer>
+ </map>
+ <key>LastSnapshotToEmailWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>The width of the last email snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1024</integer>
+ </map>
+ <key>LastSnapshotToDiskHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>The height of the last disk snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>768</integer>
+ </map>
+ <key>LastSnapshotToDiskWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>The width of the last disk snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1024</integer>
+ </map>
+ <key>LastSnapshotToInventoryHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>The height of the last texture snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>512</integer>
+ </map>
+ <key>LastSnapshotToInventoryWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>The width of the last texture snapshot, in px</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>512</integer>
+ </map>
+ <key>LastSnapshotType</key>
+ <map>
+ <key>Comment</key>
+ <string>Select this as next type of snapshot to take (0 = postcard, 1 = texture, 2 = local image)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LeftClickShowMenu</key>
+ <map>
+ <key>Comment</key>
+ <string>Left click opens pie menu (FALSE = left click touches or grabs object)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LimitDragDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Limit translation of object via translate tool</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LimitSelectDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Disallow selection of objects beyond max select distance</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LipSyncAah</key>
+ <map>
+ <key>Comment</key>
+ <string>Aah (jaw opening) babble loop</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>257998776531013446642343</string>
+ </map>
+ <key>LipSyncAahPowerTransfer</key>
+ <map>
+ <key>Comment</key>
+ <string>Transfer curve for Voice Interface power to aah lip sync amplitude</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>0000123456789</string>
+ </map>
+ <key>LipSyncEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>0 disable lip-sync, 1 enable babble loop</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LipSyncOoh</key>
+ <map>
+ <key>Comment</key>
+ <string>Ooh (mouth width) babble loop</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>1247898743223344444443200000</string>
+ </map>
+ <key>LipSyncOohAahRate</key>
+ <map>
+ <key>Comment</key>
+ <string>Rate to babble Ooh and Aah (/sec)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>24.0</real>
+ </map>
+ <key>LipSyncOohPowerTransfer</key>
+ <map>
+ <key>Comment</key>
+ <string>Transfer curve for Voice Interface power to ooh lip sync amplitude</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>0012345566778899</string>
+ </map>
+ <key>LocalCacheVersion</key>
+ <map>
+ <key>Comment</key>
+ <string>Version number of cache</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LocalFileSystemBrowsingEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable/disable access to the local file system via the file picker</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LoginSRVTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Duration in seconds of the login SRV request timeout</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>LoginSRVPump</key>
+ <map>
+ <key>Comment</key>
+ <string>Name of the message pump that handles SRV request</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>LLAres</string>
+ </map>
+ <key>LogMessages</key>
+ <map>
+ <key>Comment</key>
+ <string>Log network traffic</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LogTextureNetworkTraffic</key>
+ <map>
+ <key>Comment</key>
+ <string>Log network traffic for textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LoginAsGod</key>
+ <map>
+ <key>Comment</key>
+ <string>Attempt to login with god powers (Linden accounts only)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LoginLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Login location ('last', 'home')</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>last</string>
+ </map>
+ <key>LoginPage</key>
+ <map>
+ <key>Comment</key>
+ <string>Login authentication page.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>LosslessJ2CUpload</key>
+ <map>
+ <key>Comment</key>
+ <string>Use lossless compression for small image uploads</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MainloopTimeoutDefault</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout duration for mainloop lock detection, in seconds.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>20.0</real>
+ </map>
+ <key>MapOverlayIndex</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently selected world map type</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MapScale</key>
+ <map>
+ <key>Comment</key>
+ <string>World map zoom level (pixels per region)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>128.0</real>
+ </map>
+ <key>MapServerURL</key>
+ <map>
+ <key>Comment</key>
+ <string>World map URL template for locating map tiles</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://map.secondlife.com.s3.amazonaws.com/</string>
+ </map>
+ <key>CurrentMapServerURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Current Session World map URL</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>MapShowEvents</key>
+ <map>
+ <key>Comment</key>
+ <string>Show events on world map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MapShowInfohubs</key>
+ <map>
+ <key>Comment</key>
+ <string>Show infohubs on the world map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MapShowLandForSale</key>
+ <map>
+ <key>Comment</key>
+ <string>Show land for sale on world map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MapShowPeople</key>
+ <map>
+ <key>Comment</key>
+ <string>Show other users on world map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MapShowTelehubs</key>
+ <map>
+ <key>Comment</key>
+ <string>Show telehubs on world map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MiniMapAutoCenter</key>
+ <map>
+ <key>Comment</key>
+ <string>Center the focal point of the minimap.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>Marker</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>MarketplaceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/</string>
+ </map>
+ <key>MarketplaceURL_objectFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Attachments Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/attachments</string>
+ </map>
+ <key>MarketplaceURL_objectMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Attachments Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/attachments</string>
+ </map>
+ <key>MarketplaceURL_clothingFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Clothing Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/clothing_female_avatar</string>
+ </map>
+ <key>MarketplaceURL_clothingMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Clothing Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/clothing_male_avatar</string>
+ </map>
+ <key>MarketplaceURL_bodypartFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Bodyparts Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com</string>
+ </map>
+ <key>MarketplaceURL_bodypartMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Bodyparts Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/</string>
+ </map>
+ <key>MarketplaceURL_glovesMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Gloves Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/gloves_both_women_and_men</string>
+ </map>
+ <key>MarketplaceURL_glovesFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Gloves Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/gloves_both_women_and_men</string>
+ </map>
+ <key>MarketplaceURL_jacketFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Jacket Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/jacket_womens</string>
+ </map>
+ <key>MarketplaceURL_jacketMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Jacket Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/jacket_mens</string>
+ </map>
+ <key>MarketplaceURL_shirtFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shirt Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/shirt_womens</string>
+ </map>
+ <key>MarketplaceURL_shirtMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shirt Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/shirt_mens</string>
+ </map>
+ <key>MarketplaceURL_undershirtFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Undershirt Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/undershirt_womens</string>
+ </map>
+ <key>MarketplaceURL_undershirtMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Undershirt Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/undershirt_mens</string>
+ </map>
+ <key>MarketplaceURL_skirtFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Skirt Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/skirts_women</string>
+ </map>
+ <key>MarketplaceURL_skirtMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Skirt Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/skirts_women</string>
+ </map>
+ <key>MarketplaceURL_pantsFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Pants Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/pants_women</string>
+ </map>
+ <key>MarketplaceURL_pantsMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Pants Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/pants_men</string>
+ </map>
+ <key>MarketplaceURL_underpantsFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Underwear Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/underwear_women</string>
+ </map>
+ <key>MarketplaceURL_underpantsMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Underwear Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/underwear_men</string>
+ </map>
+ <key>MarketplaceURL_shoesFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shoes Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/shoes_women</string>
+ </map>
+ <key>MarketplaceURL_shoesMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shoes Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/shoes_men</string>
+ </map>
+ <key>MarketplaceURL_socksFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Socks Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/socks_women</string>
+ </map>
+ <key>MarketplaceURL_socksMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Socks Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/socks_women</string>
+ </map>
+ <key>MarketplaceURL_tattooMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Tattoo Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/tattoo_both_women_and_men</string>
+ </map>
+ <key>MarketplaceURL_tattooFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Tattoo Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/tattoo_both_women_and_men</string>
+ </map>
+ <key>MarketplaceURL_hairFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Hair Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_hair</string>
+ </map>
+ <key>MarketplaceURL_hairMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Hair Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_hair</string>
+ </map>
+ <key>MarketplaceURL_eyesFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Eyes Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_eyes</string>
+ </map>
+ <key>MarketplaceURL_eyesMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Eyes Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_eyes</string>
+ </map>
+ <key>MarketplaceURL_shapeFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shape Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_shape</string>
+ </map>
+ <key>MarketplaceURL_shapeMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Shape Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_shape</string>
+ </map>
+ <key>MarketplaceURL_skinFemale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Skin Female</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/womens_skin</string>
+ </map>
+ <key>MarketplaceURL_skinMale</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to the Marketplace Skins Male</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://marketplace.secondlife.com/trampoline/viewer21/mens_skin</string>
+ </map>
+ <key>MaxDragDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum allowed translation distance in a single operation of translate tool (meters from start point)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>48.0</real>
+ </map>
+ <key>MaxSelectDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum allowed selection distance (meters from avatar)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>64.0</real>
+ </map>
+ <key>MaxWearableWaitTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Max seconds to wait for wearable assets to fetch.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>60.0</real>
+ </map>
+ <key>MediaControlFadeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of time (in seconds) that the media control fades</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.5</real>
+ </map>
+ <key>MediaControlTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of time (in seconds) for media controls to fade with no mouse activity</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>3.0</real>
+ </map>
+ <key>MediaEnablePopups</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, enable targeted links and javascript in media to open new media browser windows without a prompt.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MediaOnAPrimUI</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to show the "link sharing" UI</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MediaPerformanceManagerDebug</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to show debug data for the media performance manager in the nearby media list.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MediaShowOnOthers</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to show media on other avatars</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MediaShowOutsideParcel</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to show media from outside the current parcel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MediaShowWithinParcel</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to show media within the current parcel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MediaTentativeAutoPlay</key>
+ <map>
+ <key>Comment</key>
+ <string>This is a tentative flag that may be temporarily set off by the user, until she teleports</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MemoryLogFrequency</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds between display of Memory in log (0 for never)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>600.0</real>
+ </map>
+ <key>MemProfiling</key>
+ <map>
+ <key>Comment</key>
+ <string>You want to use tcmalloc's memory profiling options.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MenuAccessKeyTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Time (seconds) in which the menu key must be tapped to move focus to the menu bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>MenuBarHeight</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>18</integer>
+ </map>
+ <key>MenuBarWidth</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>410</integer>
+ </map>
+ <key>MePanelOpened</key>
+ <map>
+ <key>Comment</key>
+ <string>Indicates that Me Panel was opened at least once after Viewer was installed</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+ <key>MeshEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Expose UI for mesh functionality (may require restart to take effect).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
+ <key>MeshImportUseSLM</key>
+ <map>
+ <key>Comment</key>
+ <string>Use cached copy of last upload for a dae if available instead of loading dae file from scratch.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+ <key>MigrateCacheDirectory</key>
+ <map>
+ <key>Comment</key>
+ <string>Check for old version of disk cache to migrate to current location</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MiniMapPrimMaxRadius</key>
+ <map>
+ <key>Comment</key>
+ <string>Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>256.0</real>
+ </map>
+ <key>MiniMapRotate</key>
+ <map>
+ <key>Comment</key>
+ <string>Rotate miniature world map to avatar direction</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>MiniMapScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Miniature world map zoom level (pixels per region)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>128.0</real>
+ </map>
+ <key>MouseSensitivity</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls responsiveness of mouse when in mouselook mode (fraction or multiple of default mouse sensitivity)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>3.0</real>
+ </map>
+ <key>MouseSmooth</key>
+ <map>
+ <key>Comment</key>
+ <string>Smooths out motion of mouse when in mouselook mode.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MouseSun</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteAmbient</key>
+ <map>
+ <key>Comment</key>
+ <string>Ambient sound effects, such as wind noise, play at 0 volume</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteAudio</key>
+ <map>
+ <key>Comment</key>
+ <string>All audio plays at 0 volume (streaming audio still takes up bandwidth, for example)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteMedia</key>
+ <map>
+ <key>Comment</key>
+ <string>Media plays at 0 volume (streaming audio still takes up bandwidth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteMusic</key>
+ <map>
+ <key>Comment</key>
+ <string>Music plays at 0 volume (streaming audio still takes up bandwidth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteSounds</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound effects play at 0 volume</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteUI</key>
+ <map>
+ <key>Comment</key>
+ <string>UI sound effects play at 0 volume</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteVoice</key>
+ <map>
+ <key>Comment</key>
+ <string>Voice plays at 0 volume (streaming audio still takes up bandwidth)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MuteWhenMinimized</key>
+ <map>
+ <key>Comment</key>
+ <string>Mute audio when SL window is minimized</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>MyOutfitsAutofill</key>
+ <map>
+ <key>Comment</key>
+ <string>Always autofill My Outfits from library when empty (else happens just once).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NearMeRange</key>
+ <map>
+ <key>Comment</key>
+ <string>Search radius for nearby avatars</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <integer>130</integer>
+ </map>
+ <key>NextOwnerCopy</key>
+ <map>
+ <key>Comment</key>
+ <string>Newly created objects can be copied by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NextOwnerModify</key>
+ <map>
+ <key>Comment</key>
+ <string>Newly created objects can be modified by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NextOwnerTransfer</key>
+ <map>
+ <key>Comment</key>
+ <string>Newly created objects can be resold or given away by next owner</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NewCacheLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Change the location of the local disk cache to this</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>NewCacheLocationTopFolder</key>
+ <map>
+ <key>Comment</key>
+ <string>Change the top folder location of the local disk cache to this</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>NextLoginLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Location to log into by default.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>NoAudio</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable audio playback.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NoHardwareProbe</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable hardware probe.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NoInventoryLibrary</key>
+ <map>
+ <key>Comment</key>
+ <string>Do not request inventory library.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NoPreload</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable sound and image preload.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NoVerifySSLCert</key>
+ <map>
+ <key>Comment</key>
+ <string>Do not verify SSL peers.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NotifyBoxHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Height of notification messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>200</integer>
+ </map>
+ <key>NotifyBoxWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Width of notification messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>305</integer>
+ </map>
+ <key>NotificationToastLifeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a notification toast exists</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>NotificationTipToastLifeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a notification tip toast exist</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>ToastFadingTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a toast is fading </string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NearbyToastFadingTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a nearby chat toast is fading </string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>NearbyToastLifeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a nearby chat toast exists</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>23</integer>
+ </map>
+ <key>StartUpToastLifeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds while a StartUp toast exist</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>ToastGap</key>
+ <map>
+ <key>Comment</key>
+ <string>Gap between toasts on a screen (min. value is 5)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>7</integer>
+ </map>
+ <key>ToastButtonWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Default width of buttons in the toast.
+ Notes:
+ If required width will be less then this one, a button will be reshaped to default size , otherwise to required
+ Change of this parameter will affect the layout of buttons in notification toast.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>90</integer>
+ </map>
+ <key>ChannelBottomPanelMargin</key>
+ <map>
+ <key>Comment</key>
+ <string>Space from a lower toast to the Bottom Tray</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>35</integer>
+ </map>
+ <key>NotificationChannelRightMargin</key>
+ <map>
+ <key>Comment</key>
+ <string>Space between toasts and a right border of an area where they can appear</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>NotificationChannelHeightRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Notification channel and World View ratio(0.0 - always show 1 notification, 1.0 - max ratio).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>OverflowToastHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Height of an overflow toast</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>72</integer>
+ </map>
+ <key>NotifyMoneyChange</key>
+ <map>
+ <key>Comment</key>
+ <string>Pop up notifications for all L$ transactions</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NotifyTipDuration</key>
+ <map>
+ <key>Comment</key>
+ <string>Length of time that notification tips stay on screen (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>4.0</real>
+ </map>
+ <key>NumSessions</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of successful logins to Second Life</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NumpadControl</key>
+ <map>
+ <key>Comment</key>
+ <string>How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ObjectCacheEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable the object cache.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatAdvanced</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand advanced performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OpenDebugStatBasic</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand basic performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatNet</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand network stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatRender</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand render stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatSim</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand simulator performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OpenDebugStatTexture</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Texture performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OpenDebugStatPhysicsDetails</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Physics Details performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OpenDebugStatSimTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Simulator Time performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OpenDebugStatSimTimeDetails</key>
+ <map>
+ <key>Comment</key>
+ <string>Expand Simulator Time Details performance stats display</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OutBandwidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Outgoing bandwidth throttle (bps)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>OverlayTitle</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls watermark text message displayed on screen when "ShowOverlayTitle" is enabled (one word, underscores become spaces)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Set_via_OverlayTitle_in_settings.xml</string>
+ </map>
+ <key>PTTCurrentlyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Push to Talk mode</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PacketDropPercentage</key>
+ <map>
+ <key>Comment</key>
+ <string>Percentage of packets dropped by the client.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>ObjectCostHighThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Threshold at which object cost is considered high (displayed in red).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>50.0</real>
+ </map>
+ <key>ObjectCostLowColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Color for object with a low object cost.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>0.0</real>
+ <real>0.5</real>
+ <real>1.0</real>
+ <real>0.5</real>
+ </array>
+ </map>
+ <key>ObjectCostMidColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Color for object with a medium object cost.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.75</real>
+ <real>0.0</real>
+ <real>0.65</real>
+ </array>
+ </map>
+ <key>ObjectCostHighColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Color for object a high object cost.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.75</real>
+ </array>
+ </map>
+
+ <key>ParcelMediaAutoPlayEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Auto play parcel media when available</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ParticipantListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in participant list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PerAccountSettingsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Persisted client settings file name (per user).</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>PermissionsCautionEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>When enabled, changes the handling of script permission requests to help avoid accidental granting of certain permissions, such as the debit permission</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PermissionsCautionNotifyBoxHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Height of caution-style notification messages</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>344</integer>
+ </map>
+ <key>PickerContextOpacity</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls overall opacity of context frustrum connecting color and texture pickers with their swatches</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.34999999404</real>
+ </map>
+ <key>PicksPerSecondMouseMoving</key>
+ <map>
+ <key>Comment</key>
+ <string>How often to perform hover picks while the mouse is moving (picks per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>PicksPerSecondMouseStationary</key>
+ <map>
+ <key>Comment</key>
+ <string>How often to perform hover picks while the mouse is stationary (picks per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>PieMenuLineWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Width of lines in pie menu display (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>2.5</real>
+ </map>
+ <key>PingInterpolate</key>
+ <map>
+ <key>Comment</key>
+ <string>Extrapolate object position along velocity vector based on ping delay</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>PitchFromMousePosition</key>
+ <map>
+ <key>Comment</key>
+ <string>Vertical range over which avatar head tracks mouse position (degrees of head rotation from top of window to bottom)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>90.0</real>
+ </map>
+ <key>PlayTypingAnim</key>
+ <map>
+ <key>Comment</key>
+ <string>Your avatar plays the typing animation whenever you type in the chat bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PluginAttachDebuggerToPlugins</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, attach a debugger session to each plugin process as it's launched.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>PluginInstancesCPULimit</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.9</real>
+ </map>
+
+ <key>PlainTextChatHistory</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable/Disable plain text chat history style</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>PluginInstancesLow</key>
+ <map>
+ <key>Comment</key>
+ <string>Limit on the number of inworld media plugins that will run at "low" priority</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>PluginInstancesNormal</key>
+ <map>
+ <key>Comment</key>
+ <string>Limit on the number of inworld media plugins that will run at "normal" or higher priority</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>PluginInstancesTotal</key>
+ <map>
+ <key>Comment</key>
+ <string>Hard limit on the number of plugins that will be instantiated at once for inworld media</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>8</integer>
+ </map>
+
+ <key>PluginUseReadThread</key>
+ <map>
+ <key>Comment</key>
+ <string>Use a separate thread to read incoming messages from plugins</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>PrecachingDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Delay when logging in to load world before showing it (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>6.0</real>
+ </map>
+ <key>PreferredMaturity</key>
+ <map>
+ <key>Comment</key>
+ <string>Setting for the user's preferred maturity level (consts in indra_constants.h)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>13</integer>
+ </map>
+
+ <key>PreviewAmbientColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Ambient color of preview render.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+
+ <key>PreviewDiffuse0</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 0.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewDiffuse1</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 1.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>0.25</real>
+ <real>0.25</real>
+ <real>0.25</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewDiffuse2</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 2.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewSpecular0</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 0.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewSpecular1</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 1.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewSpecular2</key>
+ <map>
+ <key>Comment</key>
+ <string>Diffise color of preview light 2.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+
+ <key>PreviewDirection0</key>
+ <map>
+ <key>Comment</key>
+ <string>Direction of light 0 for preview render.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>-0.75</real>
+ <real>1</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>PreviewDirection1</key>
+ <map>
+ <key>Comment</key>
+ <string>Direction of light 1 for preview render.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>0.5</real>
+ <real>-0.6</real>
+ <real>0.4</real>
+ </array>
+ </map>
+
+ <key>PreviewDirection2</key>
+ <map>
+ <key>Comment</key>
+ <string>Direction of light 2 for preview render.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>0.5</real>
+ <real>-0.8</real>
+ <real>0.3</real>
+ </array>
+ </map>
+
+ <key>PrimMediaMasterEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not Media on a Prim is enabled.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PrimMediaControlsUseHoverControlSet</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not hovering over prim media uses minimal "hover" controls or the authored control set.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>PrimMediaDragNDrop</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable drag and drop of URLs onto prim faces</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PrimMediaMaxRetries</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of retries for media queries.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>PrimMediaRequestQueueDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Timer delay for fetching media from the queue (in seconds).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>PrimMediaRetryTimerDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Timer delay for retrying on media queries (in seconds).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>PrimMediaMaxSortedQueueSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of objects the viewer will load media for initially</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>100000</integer>
+ </map>
+ <key>PrimMediaMaxRoundRobinQueueSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of objects the viewer will continuously update media for</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>100000</integer>
+ </map>
+ <key>ProbeHardwareOnStartup</key>
+ <map>
+ <key>Comment</key>
+ <string>Query current hardware configuration on application startup</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>PurgeCacheOnNextStartup</key>
+ <map>
+ <key>Comment</key>
+ <string>Clear local file cache next time viewer is run</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>PurgeCacheOnStartup</key>
+ <map>
+ <key>Comment</key>
+ <string>Clear local file cache every time viewer is run</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>PushToTalkButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Which button or keyboard key is used for push-to-talk</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>MiddleMouse</string>
+ </map>
+ <key>PushToTalkToggle</key>
+ <map>
+ <key>Comment</key>
+ <string>Should the push-to-talk button behave as a toggle</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>QAMode</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Testing Features.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>QAModeEventHostPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Port on which lleventhost should listen</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>QAModeTermCode</key>
+ <map>
+ <key>Comment</key>
+ <string>On LL_ERRS, terminate with this code instead of OS message box</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>QuietSnapshotsToDisk</key>
+ <map>
+ <key>Comment</key>
+ <string>Take snapshots to disk without playing animation or sound</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>QuitAfterSeconds</key>
+ <map>
+ <key>Comment</key>
+ <string>The duration allowed before quitting.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>QuitAfterSecondsOfAFK</key>
+ <map>
+ <key>Comment</key>
+ <string>The duration allowed after being AFK before quitting.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>QuitOnLoginActivated</key>
+ <map>
+ <key>Comment</key>
+ <string>Quit if login page is activated (used when auto login is on and users must not be able to login manually)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RadioLandBrushAction</key>
+ <map>
+ <key>Comment</key>
+ <string>Last selected land modification operation (0 = flatten, 1 = raise, 2 = lower, 3 = smooth, 4 = roughen, 5 = revert)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RadioLandBrushSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of land modification brush (0 = small, 1 = medium, 2 = large)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LandBrushForce</key>
+ <map>
+ <key>Comment</key>
+ <string>Multiplier for land modification brush force.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>MediaBrowserWindowLimit</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of media brower windows that can be open at once in the media browser floater (0 for no limit)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>WebContentWindowLimit</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>5</integer>
+ </map>
+ <key>MediaRollOffRate</key>
+ <map>
+ <key>Comment</key>
+ <string>Multiplier to change rate of media attenuation</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.125</real>
+ </map>
+ <key>MediaRollOffMin</key>
+ <map>
+ <key>Comment</key>
+ <string>Adjusts the distance at which media attentuation starts</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>MediaRollOffMax</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance at which media volume is set to 0</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>30.0</real>
+ </map>
+ <key>RecentItemsSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort key for recent inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RectangleSelectInclusive</key>
+ <map>
+ <key>Comment</key>
+ <string>Select objects that have at least one vertex inside selection rectangle</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RegInClient</key>
+ <map>
+ <key>Comment</key>
+ <string>Experimental: Embed registration in login screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>QuickBuyCurrency</key>
+ <map>
+ <key>Comment</key>
+ <string>Toggle between HTML based currency purchase floater and legacy XUI version</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RegionTextureSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Terrain texture dimensions (power of 2)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>256</integer>
+ </map>
+ <key>RememberPassword</key>
+ <map>
+ <key>Comment</key>
+ <string>Keep password (in encrypted form) for next login</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderAnisotropic</key>
+ <map>
+ <key>Comment</key>
+ <string>Render textures using anisotropic filtering</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderAppleUseMultGL</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether we want to use multi-threaded OpenGL on Apple hardware (requires restart of SL).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderAttachedLights</key>
+ <map>
+ <key>Comment</key>
+ <string>Render lighted prims that are attached to avatars</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderAttachedParticles</key>
+ <map>
+ <key>Comment</key>
+ <string>Render particle systems that are attached to avatars</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Render Avatars</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderAvatarCloth</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls if avatars use wavy cloth</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderAvatarLODFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of avatars (multiplier for current screen area when calculated level of detail)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>RenderAvatarMaxVisible</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of avatars to display at any one time</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>12</integer>
+ </map>
+ <key>RenderAvatarPhysicsLODFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of avatar physics (such as breast physics).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <integer>1.0</integer>
+ </map>
+ <key>RenderAvatarVP</key>
+ <map>
+ <key>Comment</key>
+ <string>Use vertex programs to perform hardware skinning of avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderPerformanceTest</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable rendering of everything but in-world content for
+ performance testing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderLocalLights</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to render local lights.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <key>RenderShadowNearDist</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>256</real>
+ <real>256</real>
+ <real>256</real>
+ </array>
+ </map>
+ <key>RenderShadowClipPlanes</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane split distances for shadow map frusta.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>12.0</real>
+ <real>32.0</real>
+ </array>
+ </map>
+ <key>RenderShadowSplitExponent</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>3.0</real>
+ <real>3.0</real>
+ <real>2.0</real>
+ </array>
+ </map>
+ <key>RenderShadowOrthoClipPlanes</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane split distances for orthographic shadow map frusta.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>4.0</real>
+ <real>8.0</real>
+ <real>24.0</real>
+ </array>
+ </map>
+ <key>RenderShadowProjOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount to scale distance to virtual origin of shadow perspective projection.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>2.0</real>
+ </map>
+ <key>RenderShadowSlopeThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Cutoff slope value for points to affect perspective shadow generation</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>RenderShadowProjExponent</key>
+ <map>
+ <key>Comment</key>
+ <string>Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>RenderSSAOScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scaling factor for the area to sample for occluders (pixels at 1 meter away, inversely varying with distance)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>500.0</real>
+ </map>
+ <key>RenderSSAOMaxScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum screen radius for sampling (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>200</integer>
+ </map>
+ <key>RenderSSAOFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Occlusion sensitivity factor for ambient occlusion (larger is more)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.30</real>
+ </map>
+ <key>RenderSSAOEffect</key>
+ <map>
+ <key>Comment</key>
+ <string>Multiplier for (1) value and (2) saturation (HSV definition), for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>0.80</real>
+ <real>1.00</real>
+ <real>0.00</real>
+ </array>
+ </map>
+ <key>RenderBumpmapMinDistanceSquared</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum distance at which to render bumpmapped primitives (distance in meters, squared)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>100.0</real>
+ </map>
+ <key>RenderNormalMapScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scaler applied to height map when generating normal maps</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>64</real>
+ </map>
+ <key>RenderCubeMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether we can render the cube map or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderDebugAlphaMask</key>
+ <map>
+ <key>Comment</key>
+ <string>Test Alpha Masking Cutoffs.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>RenderDebugGL</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable strict GL debugging.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderDebugNormalScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of normals in debug display.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.03</real>
+ </map>
+ <key>RenderDebugPipeline</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable strict pipeline debugging.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderDebugTextureBind</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable texture bind performance test.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderDelayCreation</key>
+ <map>
+ <key>Comment</key>
+ <string>Throttle creation of drawables.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderAnimateRes</key>
+ <map>
+ <key>Comment</key>
+ <string>Animate rezing prims.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderBakeSunlight</key>
+ <map>
+ <key>Comment</key>
+ <string>Bake sunlight into vertex buffers for static objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderNoAlpha</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable rendering of alpha objects (render all alpha objects as alpha masks).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderAnimateTrees</key>
+ <map>
+ <key>Comment</key>
+ <string>Use GL matrix ops to animate tree branches.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderGIRange</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance to cut off GI effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>96</real>
+ </map>
+
+ <key>RenderGILuminance</key>
+ <map>
+ <key>Comment</key>
+ <string>Luminance factor of global illumination contribution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.075</real>
+ </map>
+
+ <key>RenderGIBrightness</key>
+ <map>
+ <key>Comment</key>
+ <string>Brightness factor of global illumination contribution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.3</real>
+ </map>
+
+ <key>RenderGINoise</key>
+ <map>
+ <key>Comment</key>
+ <string>Noise of position sampling for GI photon mapping.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.7</real>
+ </map>
+
+ <key>RenderGIAttenuation</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance attenuation factor for indirect lighting.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+
+ <key>RenderGIBlurBrightness</key>
+ <map>
+ <key>Comment</key>
+ <string>Brightness factor of global illumination blur effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.025</real>
+ </map>
+
+ <key>RenderGIBlurEdgeWeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Edge weight for GI soften filter (sharpness).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.8</real>
+ </map>
+
+ <key>RenderGIBlurIncrement</key>
+ <map>
+ <key>Comment</key>
+ <string>Increment of scale for each pass of global illumination blur effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.8</real>
+ </map>
+
+ <key>RenderLuminanceScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Luminance value scalar for darkening effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+
+ <key>RenderSunLuminanceScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Sun Luminance value scalar for darkening effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+
+ <key>RenderSunLuminanceOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Sun Luminance value offset for darkening effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+
+ <key>RenderLuminanceDetail</key>
+ <map>
+ <key>Comment</key>
+ <string>Mipmap level to use for luminance</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16.0</real>
+ </map>
+
+ <key>RenderMinimumLODTriangleCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Triangle count threshold at which automatic LOD generation stops</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+
+ <key>RenderEdgeDepthCutoff</key>
+ <map>
+ <key>Comment</key>
+ <string>Cutoff for depth difference that amounts to an edge.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.01</real>
+ </map>
+ <key>RenderEdgeNormCutoff</key>
+ <map>
+ <key>Comment</key>
+ <string>Cutoff for normal difference that amounts to an edge.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+
+ <key>RenderDeferredAlphaSoften</key>
+ <map>
+ <key>Comment</key>
+ <string>Scalar for softening alpha surfaces (for soft particles).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.75</real>
+ </map>
+ <key>RenderDeferredNoise</key>
+ <map>
+ <key>Comment</key>
+ <string>Noise scalar to hide banding in deferred render.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>4</real>
+ </map>
+ <key>RenderDeferredSpotShadowBias</key>
+ <map>
+ <key>Comment</key>
+ <string>Bias value for spot shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>-64.0</real>
+ </map>
+ <key>RenderDeferredSpotShadowOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Offset value for spot shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.8</real>
+ </map>
+
+ <key>RenderShadowBias</key>
+ <map>
+ <key>Comment</key>
+ <string>Bias value for shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>-0.008</real>
+ </map>
+ <key>RenderShadowOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Offset value for shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.01</real>
+ </map>
+ <key>RenderShadowBiasError</key>
+ <map>
+ <key>Comment</key>
+ <string>Error scale for shadow bias (based on altitude).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+ <key>RenderShadowOffsetError</key>
+ <map>
+ <key>Comment</key>
+ <string>Error scale for shadow offset (based on altitude).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+
+ <key>RenderDepthOfField</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use depth of field effect when lighting and shadows are enabled</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderSpotLightsInNondeferred</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to support projectors as spotlights when Lighting and Shadows is disabled</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderSpotShadowBias</key>
+ <map>
+ <key>Comment</key>
+ <string>Bias value for shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>-0.001</real>
+ </map>
+ <key>RenderSpotShadowOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Offset value for shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.04</real>
+ </map>
+
+ <key>RenderShadowResolutionScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of shadow map resolution vs. screen resolution</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+
+ <key>RenderDeferredTreeShadowBias</key>
+ <map>
+ <key>Comment</key>
+ <string>Bias value for tree shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderDeferredTreeShadowOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Offset value for tree shadows (prevent shadow acne).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+
+ <key>RenderHoverGlowEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Show glow effect when hovering on interactive objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderHighlightFadeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Transition time for mouseover highlights.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+
+ <key>RenderHighlightBrightness</key>
+ <map>
+ <key>Comment</key>
+ <string>Brightness of mouseover highlights.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>4.0</real>
+ </map>
+
+ <key>RenderHighlightThickness</key>
+ <map>
+ <key>Comment</key>
+ <string>Thickness of mouseover highlights.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.6</real>
+ </map>
+
+ <key>RenderHighlightColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Brightness of mouseover highlights.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>0.4</real>
+ <real>0.98</real>
+ <real>0.93</real>
+ <real>1.0</real>
+ </array>
+ </map>
+
+ <key>RenderSpecularResX</key>
+ <map>
+ <key>Comment</key>
+ <string>Spec map resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>128</real>
+ </map>
+
+ <key>RenderSpecularResY</key>
+ <map>
+ <key>Comment</key>
+ <string>Spec map resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>128</real>
+ </map>
+
+ <key>RenderSpecularExponent</key>
+ <map>
+ <key>Comment</key>
+ <string>Specular exponent for generating spec map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>8</real>
+ </map>
+
+ <key>RenderDeferred</key>
+ <map>
+ <key>Comment</key>
+ <string>Use deferred rendering pipeline.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderDeferredGI</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable GI in deferred renderer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+
+ <key>RenderDeferredSun</key>
+ <map>
+ <key>Comment</key>
+ <string>Execute sunlight shader in deferred renderer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <key>RenderDeferredAtmospheric</key>
+ <map>
+ <key>Comment</key>
+ <string>Execute atmospheric shader in deferred renderer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <key>RenderDeferredSSAO</key>
+ <map>
+ <key>Comment</key>
+ <string>Execute screen space ambient occlusion shader in deferred renderer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <key>RenderDeferredBlurLight</key>
+ <map>
+ <key>Comment</key>
+ <string>Execute shadow softening shader in deferred renderer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <key>RenderDeferredSunWash</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount local lights are washed out by sun.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>RenderShadowNoise</key>
+ <map>
+ <key>Comment</key>
+ <string>Magnitude of noise on shadow samples.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>-0.0001</real>
+ </map>
+ <key>RenderShadowErrorCutoff</key>
+ <map>
+ <key>Comment</key>
+ <string>Cutoff error value to use ortho instead of perspective projection.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>RenderShadowFOVCutoff</key>
+ <map>
+ <key>Comment</key>
+ <string>Cutoff FOV to use ortho instead of perspective projection.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.1</real>
+ </map>
+
+ <key>RenderShadowGaussian</key>
+ <map>
+ <key>Comment</key>
+ <string>Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>3.0</real>
+ <real>2.0</real>
+ <real>0.0</real>
+ </array>
+ </map>
+
+ <key>RenderShadowBlurSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of shadow softening kernel.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.4</real>
+ </map>
+ <key>RenderShadowBlurSamples</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of samples to take for each pass of shadow blur (value range 1-16). Actual number of samples is value * 2 - 1.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>4</real>
+ </map>
+ <key>RenderShadowBlurDistFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance scaler for shadow blur.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+
+ <key>RenderGIAmbiance</key>
+ <map>
+ <key>Comment</key>
+ <string>Ambiance factor of global illumination contribution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+
+ <key>RenderGIMinRenderSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Minimum size of objects to put into GI source map.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+
+ <key>RenderGIBlurColorCurve</key>
+ <map>
+ <key>Comment</key>
+ <string>Color curve for GI softening kernel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.6</real>
+ <real>0.02</real>
+ </array>
+ </map>
+
+ <key>RenderGIBlurPasses</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of GI softening kernel.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>4</real>
+ </map>
+
+ <key>RenderGIBlurSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of GI softening kernel.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>4.0</real>
+ </map>
+ <key>RenderGIBlurSamples</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of samples to take for each pass of GI blur (value range 1-16). Actual number of samples is value * 2 - 1.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+ <key>RenderGIBlurDistFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance scaler for GI blur.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+
+ <key>RenderDynamicLOD</key>
+ <map>
+ <key>Comment</key>
+ <string>Dynamically adjust level of detail.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderFSAASamples</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of samples to use for FSAA (0 = no AA).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderFarClip</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance of far clip plane from camera (meters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>256.0</real>
+ </map>
+ <key>RenderAutoMaskAlphaNonDeferred</key>
+ <map>
+ <key>Comment</key>
+ <string>Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderAutoMaskAlphaDeferred</key>
+ <map>
+ <key>Comment</key>
+ <string>Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderFlexTimeFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of flexible objects (multiplier for amount of time spent processing flex objects)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderFogRatio</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>4.0</real>
+ </map>
+ <key>RenderGamma</key>
+ <map>
+ <key>Comment</key>
+ <string>Sets gamma exponent for renderer</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>RenderGammaFull</key>
+ <map>
+ <key>Comment</key>
+ <string>Use fully controllable gamma correction, instead of faster, hard-coded gamma correction of 2.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderGlow</key>
+ <map>
+ <key>Comment</key>
+ <string>Render bloom post effect.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderGlowIterations</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of times to iterate the glow (higher = wider and smoother but slower)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>RenderGlowLumWeights</key>
+ <map>
+ <key>Comment</key>
+ <string>Weights for each color channel to be used in calculating luminance (should add up to 1.0)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>1</real>
+ <real>0</real>
+ <real>0</real>
+ </array>
+ </map>
+ <key>RenderGlowMaxExtractAlpha</key>
+ <map>
+ <key>Comment</key>
+ <string>Max glow alpha value for brightness extraction to auto-glow.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>RenderGlowMinLuminance</key>
+ <map>
+ <key>Comment</key>
+ <string>Min luminance intensity necessary to consider an object bright enough to automatically glow.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>9999</real>
+ </map>
+ <key>RenderGlowResolutionPow</key>
+ <map>
+ <key>Comment</key>
+ <string>Glow map resolution power of two.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>9</integer>
+ </map>
+ <key>RenderGlowStrength</key>
+ <map>
+ <key>Comment</key>
+ <string>Additive strength of glow.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.35</real>
+ </map>
+ <key>RenderGlowWarmthAmount</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of warmth extraction to use (versus luminance extraction). 0 = lum, 1.0 = warmth</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>RenderGlowWarmthWeights</key>
+ <map>
+ <key>Comment</key>
+ <string>Weight of each color channel used before finding the max warmth</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.5</real>
+ <real>0.7</real>
+ </array>
+ </map>
+ <key>RenderGlowWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Glow sample size (higher = wider and softer but eventually more pixelated)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.3</real>
+ </map>
+ <key>RenderGround</key>
+ <map>
+ <key>Comment</key>
+ <string>Determines whether we can render the ground pool or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderHUDInSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Display HUD attachments in snapshot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderHUDParticles</key>
+ <map>
+ <key>Comment</key>
+ <string>Display particle systems in HUD attachments (experimental)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderHighlightSelections</key>
+ <map>
+ <key>Comment</key>
+ <string>Show selection outlines on objects</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderHiddenSelections</key>
+ <map>
+ <key>Comment</key>
+ <string>Show selection lines on objects that are behind other objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderHideGroupTitle</key>
+ <map>
+ <key>Comment</key>
+ <string>Don't show my group title in my name label</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NameTagShowGroupTitles</key>
+ <map>
+ <key>Comment</key>
+ <string>Show group titles in name labels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NameTagShowDisplayNames</key>
+ <map>
+ <key>Comment</key>
+ <string>Show display names in name labels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NameTagShowFriends</key>
+ <map>
+ <key>Comment</key>
+ <string>Highlight the name tags of your friends</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NameTagShowUsernames</key>
+ <map>
+ <key>Comment</key>
+ <string>Show usernames in avatar name tags</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderInitError</key>
+ <map>
+ <key>Comment</key>
+ <string>Error occured while initializing GL</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderLightRadius</key>
+ <map>
+ <key>Comment</key>
+ <string>Render the radius of selected lights</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderMaxPartCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of particles to display on screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4096</integer>
+ </map>
+ <key>RenderMaxNodeSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum size of a single node's vertex data (in KB).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>8192</integer>
+ </map>
+ <key>RenderMaxVBOSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum size of a vertex buffer (in KB).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>512</integer>
+ </map>
+ <key>RenderNameFadeDuration</key>
+ <map>
+ <key>Comment</key>
+ <string>Time interval over which to fade avatar names (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderNameShowSelf</key>
+ <map>
+ <key>Comment</key>
+ <string>Display own name above avatar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderNameShowTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Fade avatar names after specified time (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>RenderObjectBump</key>
+ <map>
+ <key>Comment</key>
+ <string>Show bumpmapping on primitives</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderQualityPerformance</key>
+ <map>
+ <key>Comment</key>
+ <string>Which graphics settings you've chosen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderReflectionDetail</key>
+ <map>
+ <key>Comment</key>
+ <string>Detail of reflection render pass.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>RenderShadowDetail</key>
+ <map>
+ <key>Comment</key>
+ <string>Detail of shadows.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+
+ <key>RenderReflectionRes</key>
+ <map>
+ <key>Comment</key>
+ <string>Reflection map resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>64</integer>
+ </map>
+ <key>RenderResolutionDivisor</key>
+ <map>
+ <key>Comment</key>
+ <string>Divisor for rendering 3D scene at reduced resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderShaderLightingMaxLevel</key>
+ <map>
+ <key>Comment</key>
+ <string>Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>RenderShaderLODThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Fraction of draw distance defining the switch to a different shader LOD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderShaderParticleThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Fraction of draw distance to not use shader on particles</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>RenderSunDynamicRange</key>
+ <map>
+ <key>Comment</key>
+ <string>Defines what percent brighter the sun is than local point lights (1.0 = 100% brighter. Value should not be less than 0. ).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderTerrainDetail</key>
+ <map>
+ <key>Comment</key>
+ <string>Detail applied to terrain texturing (0 = none, 1 or 2 = full)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>RenderTerrainLODFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of terrain (multiplier for current screen area when calculated level of detail)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderTerrainScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Terrain detail texture scale</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>12.0</real>
+ </map>
+ <key>RenderTextureMemoryMultiple</key>
+ <map>
+ <key>Comment</key>
+ <string>Multiple of texture memory value to use (should fit: 0 &lt; value &lt;= 1.0)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderTrackerBeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Display tracking arrow and beacon to target avatar, teleport destination</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderTransparentWater</key>
+ <map>
+ <key>Comment</key>
+ <string>Render water as transparent. Setting to false renders water as opaque with a simple texture applied.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderTreeLODFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of vegetation (multiplier for current screen area when calculated level of detail)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>RenderUIInSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Display user interface in snapshot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderUIBuffer</key>
+ <map>
+ <key>Comment</key>
+ <string>Cache ui render in a screen aligned buffer.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderUnloadedAvatar</key>
+ <map>
+ <key>Comment</key>
+ <string>Show avatars which haven't finished loading</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderUseTriStrips</key>
+ <map>
+ <key>Comment</key>
+ <string>Use triangle strips for rendering prims.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderUseTriStrips</key>
+ <map>
+ <key>Comment</key>
+ <string>Use triangle strips for rendering prims.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderUseFarClip</key>
+ <map>
+ <key>Comment</key>
+ <string>If false, frustum culling will ignore far clip plane.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderUseImpostors</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether we want to use impostors for far away avatars.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderUseShaderLOD</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether we want to have different shaders for LOD</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderUseShaderNearParticles</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether we want to use shaders on near particles</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderVBOEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Use GL Vertex Buffer Objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderVBOMappingDisable</key>
+ <map>
+ <key>Comment</key>
+ <string>Disable VBO glMapBufferARB</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderUseStreamVBO</key>
+ <map>
+ <key>Comment</key>
+ <string>Use VBO's for stream buffers</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderPreferStreamDraw</key>
+ <map>
+ <key>Comment</key>
+ <string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RenderVolumeLODFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>RenderWater</key>
+ <map>
+ <key>Comment</key>
+ <string>Display water</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderWaterMipNormal</key>
+ <map>
+ <key>Comment</key>
+ <string>Use mip maps for water normal map.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderWaterRefResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Water planar reflection resolution.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>512</integer>
+ </map>
+ <key>RenderParcelSelection</key>
+ <map>
+ <key>Comment</key>
+ <string>Display selected parcel outline</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RotateRight</key>
+ <map>
+ <key>Comment</key>
+ <string>Make the agent rotate to its right.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>RotationStep</key>
+ <map>
+ <key>Comment</key>
+ <string>All rotations via rotation tool are constrained to multiples of this unit (degrees)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>MeshStreamingCostScaler</key>
+ <map>
+ <key>Comment</key>
+ <string>DEBUG</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>3.0</real>
+ </map>
+ <key>MeshThreadCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of threads to use for loading meshes.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>8</integer>
+ </map>
+ <key>MeshMaxConcurrentRequests</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of threads to use for loading meshes.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>32</integer>
+ </map>
+ <key>RunMultipleThreads</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE keep background threads active during render</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SafeMode</key>
+ <map>
+ <key>Comment</key>
+ <string>Reset preferences, run in safe mode.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SaveMinidump</key>
+ <map>
+ <key>Comment</key>
+ <string>Save minidump for developer debugging on crash</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ScaleShowAxes</key>
+ <map>
+ <key>Comment</key>
+ <string>Show indicator of selected scale axis when scaling</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ScaleStretchTextures</key>
+ <map>
+ <key>Comment</key>
+ <string>Stretch textures along with object when scaling</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ScaleUniform</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale selected objects evenly about center of selection</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ScriptHelpFollowsCursor</key>
+ <map>
+ <key>Comment</key>
+ <string>Scripting help window updates contents based on script editor contents under text cursor</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ScriptsCanShowUI</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow LSL calls (such as LLMapDestination) to spawn viewer UI</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SecondLifeEnterprise</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables Second Life Enterprise features</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SelectMovableOnly</key>
+ <map>
+ <key>Comment</key>
+ <string>Select only objects you can move</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SelectOwnedOnly</key>
+ <map>
+ <key>Comment</key>
+ <string>Select only objects you own</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SelectionHighlightAlpha</key>
+ <map>
+ <key>Comment</key>
+ <string>Opacity of selection highlight (0.0 = completely transparent, 1.0 = completely opaque)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.40000000596</real>
+ </map>
+ <key>SelectionHighlightAlphaTest</key>
+ <map>
+ <key>Comment</key>
+ <string>Alpha value below which pixels are displayed on selection highlight line (0.0 = show all pixels, 1.0 = show now pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>SelectionHighlightThickness</key>
+ <map>
+ <key>Comment</key>
+ <string>Thickness of selection highlight line (fraction of view distance)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.00999999977648</real>
+ </map>
+ <key>SelectionHighlightUAnim</key>
+ <map>
+ <key>Comment</key>
+ <string>Rate at which texture animates along U direction in selection highlight line (fraction of texture per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>SelectionHighlightUScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of texture display on selection highlight line (fraction of texture size)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>SelectionHighlightVAnim</key>
+ <map>
+ <key>Comment</key>
+ <string>Rate at which texture animates along V direction in selection highlight line (fraction of texture per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
+ <key>SelectionHighlightVScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Scale of texture display on selection highlight line (fraction of texture size)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>ServerChoice</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] Controls which grid you connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShareWithGroup</key>
+ <map>
+ <key>Comment</key>
+ <string>Newly created objects are shared with the currently active group</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdvancedGraphicsSettings</key>
+ <map>
+ <key>Comment</key>
+ <string>Show advanced graphics settings</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAllObjectHoverTip</key>
+ <map>
+ <key>Comment</key>
+ <string>Show descriptive tooltip when mouse hovers over non-interactive and interactive objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AvatarNameTagMode</key>
+ <map>
+ <key>Comment</key>
+ <string>Select Avatar Name Tag Mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowAxes</key>
+ <map>
+ <key>Comment</key>
+ <string>Render coordinate frame at your position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowBanLines</key>
+ <map>
+ <key>Comment</key>
+ <string>Show in-world ban/access borders</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowBuildButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Build button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowCameraButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide View button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowConsoleWindow</key>
+ <map>
+ <key>Comment</key>
+ <string>Show log in separate OS window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NavBarShowCoordinates</key>
+ <map>
+ <key>Comment</key>
+ <string>Show coordinates in navigation bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NavBarShowParcelProperties</key>
+ <map>
+ <key>Comment</key>
+ <string>Show parcel property icons in navigation bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowBetaGrids</key>
+ <map>
+ <key>Comment</key>
+ <string>Display the beta grids in the grid selection control.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowCrosshairs</key>
+ <map>
+ <key>Comment</key>
+ <string>Display crosshairs when in mouselook mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowDebugConsole</key>
+ <map>
+ <key>Comment</key>
+ <string>Show log in SL window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowEmptyFoldersWhenSearching</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows folders that do not have any visible contents when applying a filter to inventory</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowGestureButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Gesture button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowHoverTips</key>
+ <map>
+ <key>Comment</key>
+ <string>Show descriptive tooltip when mouse hovers over items in world</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowLandHoverTip</key>
+ <map>
+ <key>Comment</key>
+ <string>Show descriptive tooltip when mouse hovers over land</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowMiniMapButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Mini-Map button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowMoveButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Move button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowScriptErrors</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script errors</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowScriptErrorsLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script error in chat or window</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowSearchButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Search button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowSnapshotButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Snapshot button button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowObjectRenderingCost</key>
+ <map>
+ <key>Comment</key>
+ <string>Show the object rendering cost in build tools</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowNavbarFavoritesPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide Navigation Bar Favorites Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowNavbarNavigationPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide Navigation Bar Navigation Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowWorldMapButton</key>
+ <map>
+ <key>Comment</key>
+ <string>Shows/Hides Map button in the bottom tray.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowMiniLocationPanel</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/Hide Mini-Location Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SidebarCameraMovement</key>
+ <map>
+ <key>Comment</key>
+ <string>Reflects world rect changing while changing sidebar visibility.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>GroupListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide group icons in the group list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FriendsListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide online and all friends icons in the friend list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FriendsListShowPermissions</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide permission icons in the friend list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>NearbyListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in nearby list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RecentListShowIcons</key>
+ <map>
+ <key>Comment</key>
+ <string>Show/hide people icons in recent list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>FriendsSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort order for friends (0 = by name, 1 = by online status)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>NearbyPeopleSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort order for nearby people (0 = by name, 3 = by distance, 4 = by most recent)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>RecentPeopleSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort order for recent people (0 = by name, 2 = by most recent)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>ShowPGSearchAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of search All that are flagged as general</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureSearchAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of search All that are flagged as moderate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultSearchAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of search All that are flagged as adult</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPGGroups</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find groups that are flagged as general</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureGroups</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find groups that are flagged as moderate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultGroups</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find groups that are flagged as adult</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPGClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find classifieds that are flagged as general</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find classifieds that are flagged as moderate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find classifieds that are flagged as adult</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPGEvents</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find events that are flagged as general</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureEvents</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find events that are flagged as moderate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultEvents</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find events that are flagged as adult</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPGLand</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find land sales that are flagged as general</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureLand</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find land sales that are flagged as moderate</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultLand</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find land sales that are flagged as adult</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPGSims</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find places or find popular that are in general sims</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowMatureSims</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find places or find popular that are in moderate sims</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowAdultSims</key>
+ <map>
+ <key>Comment</key>
+ <string>Display results of find places or find popular that are in adult sims</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>HideFromEditor</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowNearClip</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowNewInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically views new notecards/textures/landmarks</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowInInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically opens inventory to show accepted objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowObjectUpdates</key>
+ <map>
+ <key>Comment</key>
+ <string>Show when update messages are received for individual objects</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowOverlayTitle</key>
+ <map>
+ <key>Comment</key>
+ <string>Prints watermark text message on screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowParcelOwners</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPermissions</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowPropertyLines</key>
+ <map>
+ <key>Comment</key>
+ <string>Show line overlay demarking property boundaries</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowNetStats</key>
+ <map>
+ <key>Comment</key>
+ <string>Show the Status Indicators for the Viewer and Network Usage in the Status Overlay</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowSelectionBeam</key>
+ <map>
+ <key>Comment</key>
+ <string>Show selection particle beam when selecting or interacting with objects.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowStartLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Display starting location menu on login screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowTangentBasis</key>
+ <map>
+ <key>Comment</key>
+ <string>Render normal and binormal (debugging bump mapping)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowToolBar</key>
+ <map>
+ <key>Comment</key>
+ <string>Show toolbar at bottom of screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowTutorial</key>
+ <map>
+ <key>Comment</key>
+ <string>Show tutorial window on login</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowVoiceVisualizersInCalls</key>
+ <map>
+ <key>Comment</key>
+ <string>Enables in-world voice visualizers, voice gestures and lip-sync while in group or P2P calls.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SkinCurrent</key>
+ <map>
+ <key>Comment</key>
+ <string>The currently selected skin.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
+ <key>SkinningSettingsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Client skin color setting file name (per install).</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>SkyAmbientScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls strength of ambient, or non-directional light from the sun and moon (fraction or multiple of default ambient level)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.300000011921</real>
+ </map>
+ <key>SkyEditPresets</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to be able to edit the sky defaults or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SkyNightColorShift</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls moonlight color (base color applied to moon as light source)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color3</string>
+ <key>Value</key>
+ <array>
+ <real>0.67</real>
+ <real>0.67</real>
+ <real>1.0</real>
+ </array>
+ </map>
+ <key>SkyOverrideSimSunPosition</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SkySunDefaultPosition</key>
+ <map>
+ <key>Comment</key>
+ <string>Default position of sun in sky (direction in world coordinates)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>1.0</real>
+ <real>0.0</real>
+ <real>0.1</real>
+ </array>
+ </map>
+ <key>SkyUseClassicClouds</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to use the old Second Life particle clouds or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SnapEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable snapping to grid</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SnapMargin</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls maximum distance between windows before they auto-snap together (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>SnapToMouseCursor</key>
+ <map>
+ <key>Comment</key>
+ <string>When snapping to grid, center object on nearest grid point to mouse cursor</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SnapshotFormat</key>
+ <map>
+ <key>Comment</key>
+ <string>Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SnapshotLocalLastResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Take next local snapshot at this resolution</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SnapshotPostcardLastResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Take next postcard snapshot at this resolution</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SnapshotQuality</key>
+ <map>
+ <key>Comment</key>
+ <string>Quality setting of postcard JPEGs (0 = worst, 100 = best)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>75</integer>
+ </map>
+ <key>SnapshotSharingEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable uploading of snapshots to a web service.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SnapshotConfigURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to fetch Snapshot Sharing configuration data from.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://photos.apps.staging.avatarsunited.com/viewer_config</string>
+ </map>
+ <key>SnapshotTextureLastResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Take next texture snapshot at this resolution</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SpeedTest</key>
+ <map>
+ <key>Comment</key>
+ <string>Performance testing mode, no network</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>StatsAutoRun</key>
+ <map>
+ <key>Comment</key>
+ <string>Play back autopilot</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>StatsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Filename for stats logging output</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>fs.txt</string>
+ </map>
+ <key>StatsNumRuns</key>
+ <map>
+ <key>Comment</key>
+ <string>Loop autopilot playback this number of times</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>StatsPilotFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Filename for stats logging autopilot path</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>pilot.txt</string>
+ </map>
+ <key>StatsPilotXMLFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Filename for stats logging extended autopilot path</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>pilot.xml</string>
+ </map>
+ <key>StatsQuitAfterRuns</key>
+ <map>
+ <key>Comment</key>
+ <string>Quit application after this number of autopilot playback runs</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>StatsSessionTrackFrameStats</key>
+ <map>
+ <key>Comment</key>
+ <string>Track rendering and network statistics</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>StatsSummaryFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Filename for stats logging summary</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>fss.txt</string>
+ </map>
+ <key>SystemLanguage</key>
+ <map>
+ <key>Comment</key>
+ <string>Language indicated by system settings (for UI)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>en</string>
+ </map>
+ <key>TabToTextFieldsOnly</key>
+ <map>
+ <key>Comment</key>
+ <string>TAB key takes you to next text entry field, instead of next widget</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TerrainColorHeightRange</key>
+ <map>
+ <key>Comment</key>
+ <string>Altitude range over which a given terrain texture has effect (meters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>60.0</real>
+ </map>
+ <key>TerrainColorStartHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Starting altitude for terrain texturing (meters)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>20.0</real>
+ </map>
+ <key>TextureDecodeDisabled</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE, do not fetch and decode any textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureDisable</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE, do not load textures for in-world content</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureDiscardLevel</key>
+ <map>
+ <key>Comment</key>
+ <string>Specify texture resolution (0 = highest, 5 = lowest)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureLoadFullRes</key>
+ <map>
+ <key>Comment</key>
+ <string>If TRUE, always load textures at full resolution (discard = 0)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureMemory</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of memory to use for textures in MB (0 = autodetect)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TexturePickerShowFolders</key>
+ <map>
+ <key>Comment</key>
+ <string>Show folders with no texures in texture picker</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>TexturePickerSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>ThrottleBandwidthKBPS</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum allowable downstream bandwidth (kilo bits per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>500.0</real>
+ </map>
+ <key>UpdaterMaximumBandwidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum allowable downstream bandwidth for updater service (kilo bits per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>500.0</real>
+ </map>
+ <key>ToolTipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying tooltip when mouse stops over UI element</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.699999988079</real>
+ </map>
+ <key>ToolTipFadeTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds over which tooltip fades away</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.2</real>
+ </map>
+ <key>ToolTipVisibleTimeFar</key>
+ <map>
+ <key>Comment</key>
+ <string>Fade tooltip after after time passes (seconds) while mouse not near tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>ToolTipVisibleTimeNear</key>
+ <map>
+ <key>Comment</key>
+ <string>Fade tooltip after after time passes (seconds) while mouse near tooltip or original position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>ToolTipVisibleTimeOver</key>
+ <map>
+ <key>Comment</key>
+ <string>Fade tooltip after after time passes (seconds) while mouse over tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1000.0</real>
+ </map>
+ <key>ToolboxAutoMove</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TrackFocusObject</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera tracks last object zoomed on</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>TranslateLanguage</key>
+ <map>
+ <key>Comment</key>
+ <string>Translate Language specifier</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>default</string>
+ </map>
+ <key>TranslateChat</key>
+ <map>
+ <key>Comment</key>
+ <string>Translate incoming chat messages</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TutorialURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for tutorial menu item, set automatically during login</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>TypeAheadTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Time delay before clearing type-ahead buffer in lists (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.5</real>
+ </map>
+ <key>UIAutoScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Keep UI scale consistent across different resolutions</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UIAvatariconctrlSymbolHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Avatar Icon Control Symbol Horizontal Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>2</real>
+ </map>
+ <key>UIAvatariconctrlSymbolVPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Avatar Icon Control Symbol Vertical Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>2</real>
+ </map>
+ <key>UIAvatariconctrlSymbolSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Avatar Icon Control Symbol Size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>5</real>
+ </map>
+ <key>UIAvatariconctrlSymbolPosition</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Avatar Icon Control Symbol Position (TopLeft|TopRight|BottomLeft|BottomRight)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>BottomRight</string>
+ </map>
+ <key>UIButtonOrigHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Button Original Horizontal Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>6</real>
+ </map>
+ <key>UICheckboxctrlBtnSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Checkbox Control Button Size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>13</real>
+ </map>
+ <key>UICheckboxctrlHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Checkbox Control Height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+ <key>UICheckboxctrlHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Checkbox Control Horizontal Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>2</real>
+ </map>
+ <key>UICheckboxctrlSpacing</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Checkbox Control Spacing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>5</real>
+ </map>
+ <key>UICheckboxctrlVPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Checkbox Control Vertical Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>2</real>
+ </map>
+ <key>UICloseBoxFromTop</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance from top of floater to top of close box icon, pixels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>5</real>
+ </map>
+ <key>UIExtraTriangleHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>UI extra triangle height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>-2</real>
+ </map>
+ <key>UIExtraTriangleWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>UI extra triangle width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>2</real>
+ </map>
+ <key>UIFloaterCloseBoxSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI floater close box size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+ <key>UIFloaterHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI floater horizontal pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>6</real>
+ </map>
+ <key>UIFloaterTestBool</key>
+ <map>
+ <key>Comment</key>
+ <string>Example saved setting for the test floater</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UIFloaterTitleVPad</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance from top of floater to top of title string, pixels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>7</real>
+ </map>
+ <key>UIImgDefaultEyesUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>6522e74d-1660-4e7f-b601-6f48c1659a77</string>
+ </map>
+ <key>UIImgDefaultGlovesUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultHairUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>7ca39b4c-bd19-4699-aff7-f93fd03d3e7b</string>
+ </map>
+ <key>UIImgDefaultJacketUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultPantsUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultShirtUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultShoesUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultSkirtUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultSocksUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultAlphaUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UIImgDefaultUnderwearUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>StartUpChannelUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>B56AF90D-6684-48E4-B1E4-722D3DEB2CB6</string>
+ </map>
+ <key>NearByChatChannelUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>E1158BD6-661C-4981-9DAD-4DCBFF062502</string>
+ </map>
+ <key>NotificationChannelUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>AEED3193-8709-4693-8558-7452CCA97AE5</string>
+ </map>
+ <key>AlertChannelUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>F3E07BC8-A973-476D-8C7F-F3B7293975D1</string>
+ </map>
+ <key>UIImgWhiteUUID</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5748decc-f629-461c-9a36-a35a221fe21f</string>
+ </map>
+ <key>UILineEditorCursorThickness</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Line Editor Cursor Thickness</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>UIMaxComboWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum width of combo box</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>500</real>
+ </map>
+ <key>UIMinimizedWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI floater minimized width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>160</real>
+ </map>
+ <key>UIMultiSliderctrlSpacing</key>
+ <map>
+ <key>Comment</key>
+ <string>UI multi slider ctrl spacing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>4</real>
+ </map>
+ <key>UIMultiTrackHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>UI multi track height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>6</real>
+ </map>
+ <key>UIPreeditMarkerBrightness</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Marker Brightness</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.4</real>
+ </map>
+ <key>UIPreeditMarkerGap</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Marker Gap</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
+ <key>UIPreeditMarkerPosition</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Marker Position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>UIPreeditMarkerThickness</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Marker Thickness</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
+ <key>UIPreeditStandoutBrightness</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Standout Brightness</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.6</real>
+ </map>
+ <key>UIPreeditStandoutGap</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Standout Gap</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
+ <key>UIPreeditStandoutPosition</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Standout Position</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>UIPreeditStandoutThickness</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Preedit Standout Thickness</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>UIResizeBarHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI resize bar height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>3</real>
+ </map>
+ <key>UIResizeBarOverlap</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI resize bar overlap</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>1</real>
+ </map>
+ <key>UIScaleFactor</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of UI relative to default layout on 1024x768 screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1.0</real>
+ </map>
+ <key>UIScrollbarSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI scrollbar size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>15</real>
+ </map>
+ <key>UISliderctrlHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>UI slider ctrl height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+ <key>UISliderctrlSpacing</key>
+ <map>
+ <key>Comment</key>
+ <string>UI slider ctrl spacing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>4</real>
+ </map>
+ <key>UISndAlert</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for alerts (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>ed124764-705d-d497-167a-182cd9fa2e6c</string>
+ </map>
+ <key>UISndBadKeystroke</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for invalid keystroke (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>2ca849ba-2885-4bc3-90ef-d4987a5b983a</string>
+ </map>
+ <key>UISndClick</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for mouse click (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6</string>
+ </map>
+ <key>UISndClickRelease</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for mouse button release (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6</string>
+ </map>
+ <key>UISndDebugSpamToggle</key>
+ <map>
+ <key>Comment</key>
+ <string>Log UI sound effects as they are played</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UISndHealthReductionF</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for female pain (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>219c5d93-6c09-31c5-fb3f-c5fe7495c115</string>
+ </map>
+ <key>UISndHealthReductionM</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for male pain (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>e057c244-5768-1056-c37e-1537454eeb62</string>
+ </map>
+ <key>UISndHealthReductionThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of health reduction required to trigger "pain" sound</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>UISndInvalidOp</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for invalid operations (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>4174f859-0d3d-c517-c424-72923dc21f65</string>
+ </map>
+ <key>UISndMoneyChangeDown</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for L$ balance increase (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>104974e3-dfda-428b-99ee-b0d4e748d3a3</string>
+ </map>
+ <key>UISndMoneyChangeThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount of change in L$ balance required to trigger "money" sound</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>50.0</real>
+ </map>
+ <key>UISndMoneyChangeUp</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for L$ balance decrease(uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>77a018af-098e-c037-51a6-178f05877c6f</string>
+ </map>
+ <key>UISndNewIncomingIMSession</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for new instant message session(uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>67cc2844-00f3-2b3c-b991-6418d01e1bb7</string>
+ </map>
+ <key>UISndObjectCreate</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for object creation (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>f4a0660f-5446-dea2-80b7-6482a082803c</string>
+ </map>
+ <key>UISndObjectDelete</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for object deletion (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>0cb7b00a-4c10-6948-84de-a93c09af2ba9</string>
+ </map>
+ <key>UISndObjectRezIn</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for rezzing objects (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>3c8fc726-1fd6-862d-fa01-16c5b2568db6</string>
+ </map>
+ <key>UISndObjectRezOut</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for derezzing objects (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>00000000-0000-0000-0000-000000000000</string>
+ </map>
+ <key>UISndSnapshot</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for taking a snapshot (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>3d09f582-3851-c0e0-f5ba-277ac5c73fb4</string>
+ </map>
+ <key>UISndStartIM</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for starting a new IM session (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>c825dfbc-9827-7e02-6507-3713d18916c1</string>
+ </map>
+ <key>UISndTeleportOut</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for teleporting (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>d7a9a565-a013-2a69-797d-5332baa1a947</string>
+ </map>
+ <key>UISndTyping</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for starting to type a chat message (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>5e191c7b-8996-9ced-a177-b2ac32bfea06</string>
+ </map>
+ <key>UISndWindowClose</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for closing a window (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>2c346eda-b60c-ab33-1119-b8941916a499</string>
+ </map>
+ <key>UISndWindowOpen</key>
+ <map>
+ <key>Comment</key>
+ <string>Sound file for opening a window (uuid for sound asset)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>c80260ba-41fd-8a46-768a-6bf236360e3a</string>
+ </map>
+ <key>UISpinctrlBtnHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>UI spin control button height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>11</integer>
+ </map>
+ <key>UISpinctrlBtnWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>UI spin control button width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>16</integer>
+ </map>
+ <key>UISpinctrlDefaultLabelWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>UI spin control default label width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>UISpinctrlSpacing</key>
+ <map>
+ <key>Comment</key>
+ <string>UI spin control spacing</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>UITabCntrArrowBtnSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Arrow Button Size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>16</integer>
+ </map>
+ <key>UITabCntrvArrowBtnSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container V Arrow Button Size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>16</integer>
+ </map>
+ <key>UITabCntrvPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container V Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UITabCntrButtonPanelOverlap</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Button Panel Overlap</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UITabCntrCloseBtnSize</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Close Button Size</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>16</integer>
+ </map>
+ <key>UITabCntrTabHPad</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Tab Horizontal Pad</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
+ <key>UITabCntrTabPartialWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Tab Partial Width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>12</integer>
+ </map>
+ <key>UITabCntrVertTabMinWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Container Vertical Tab Minimum Width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>100</integer>
+ </map>
+ <key>UITabPadding</key>
+ <map>
+ <key>Comment</key>
+ <string>UI Tab Padding</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>15</integer>
+ </map>
+ <key>UpdaterServiceSetting</key>
+ <map>
+ <key>Comment</key>
+ <string>Configure updater service.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>UpdaterServiceCheckPeriod</key>
+ <map>
+ <key>Comment</key>
+ <string>Default period between update checking.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>3600</integer>
+ </map>
+ <key>UpdaterServiceURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Default location for the updater service.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://update.secondlife.com</string>
+ </map>
+ <key>UpdaterServicePath</key>
+ <map>
+ <key>Comment</key>
+ <string>Path on the update server host.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>update</string>
+ </map>
+ <key>UpdaterServiceProtocolVersion</key>
+ <map>
+ <key>Comment</key>
+ <string>The update protocol version to use.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>v1.0</string>
+ </map>
+ <key>UploadBakedTexOld</key>
+ <map>
+ <key>Comment</key>
+ <string>Forces the baked texture pipeline to upload using the old method.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseAltKeyForMenus</key>
+ <map>
+ <key>Comment</key>
+ <string>Access menus via keyboard by tapping Alt</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseChatBubbles</key>
+ <map>
+ <key>Comment</key>
+ <string>Show chat above avatars head in chat bubbles</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseCircuitCodeMaxRetries</key>
+ <map>
+ <key>Comment</key>
+ <string>Max timeout count for the initial UseCircuitCode message</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>3</real>
+ </map>
+ <key>UseCircuitCodeTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout duration in seconds for the initial UseCircuitCode message</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
+ <key>UseDebugLogin</key>
+ <map>
+ <key>Comment</key>
+ <string>Provides extra control over which grid to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseDebugMenus</key>
+ <map>
+ <key>Comment</key>
+ <string>Turns on "Debug" menu</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseDefaultColorPicker</key>
+ <map>
+ <key>Comment</key>
+ <string>Use color picker supplied by operating system</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseDisplayNames</key>
+ <map>
+ <key>Comment</key>
+ <string>Use new, changeable, unicode names</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseEnergy</key>
+ <map>
+ <key>Comment</key>
+ <string />
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseExternalBrowser</key>
+ <map>
+ <key>Comment</key>
+ <string>Use default browser when opening web pages instead of in-world browser.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseFreezeFrame</key>
+ <map>
+ <key>Comment</key>
+ <string>Freeze time when taking snapshots.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseOcclusion</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable object culling based on occlusion (coverage) by other objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>RenderDelayVBUpdate</key>
+ <map>
+ <key>Comment</key>
+ <string>Delay vertex buffer updates until just before rendering</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SpeakerParticipantDefaultOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Order for displaying speakers in voice controls. 0 = alphabetical. 1 = recent.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SpeakerParticipantRemoveDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>UseNewWalkRun</key>
+ <map>
+ <key>Comment</key>
+ <string>Replace standard walk/run animations with new ones.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseStartScreen</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to load a start screen image or not.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseWebPagesOnPrims</key>
+ <map>
+ <key>Comment</key>
+ <string>[NOT USED]</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UserConnectionPort</key>
+ <map>
+ <key>Comment</key>
+ <string>Port that this client transmits on.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UserLogFile</key>
+ <map>
+ <key>Comment</key>
+ <string>User specified log file name.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>UserLoginInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Users loging data.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ </map>
+ <key>VFSOldSize</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] Controls resizing of local file cache</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VFSSalt</key>
+ <map>
+ <key>Comment</key>
+ <string>[DO NOT MODIFY] Controls local file caching behavior</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VectorizeEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable general vector operations and data alignment.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VectorizePerfTest</key>
+ <map>
+ <key>Comment</key>
+ <string>Test SSE/vectorization performance and choose fastest version.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VectorizeProcessor</key>
+ <map>
+ <key>Comment</key>
+ <string>0=Compiler Default, 1=SSE, 2=SSE2, autodetected</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VectorizeSkin</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable vector operations for avatar skinning.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VelocityInterpolate</key>
+ <map>
+ <key>Comment</key>
+ <string>Extrapolate object motion from last packet based on received velocity</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>InterpolationTime</key>
+ <map>
+ <key>Comment</key>
+ <string>How long to extrapolate object motion after last packet received</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>InterpolationPhaseOut</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds to phase out interpolated motion</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VerboseLogs</key>
+ <map>
+ <key>Comment</key>
+ <string>Display source file and line number for each log item for debugging purposes</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VertexShaderEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable/disable all GLSL shaders (debug)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VivoxAutoPostCrashDumps</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, SLVoice will automatically send crash dumps directly to Vivox.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VivoxDebugLevel</key>
+ <map>
+ <key>Comment</key>
+ <string>Logging level to use when launching the vivox daemon</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>-1</string>
+ </map>
+ <key>VivoxDebugSIPURIHostName</key>
+ <map>
+ <key>Comment</key>
+ <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>VivoxDebugVoiceAccountServerURI</key>
+ <map>
+ <key>Comment</key>
+ <string>URI to the vivox account management server (empty string for the default).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>VivoxVoiceHost</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice host to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>127.0.0.1</string>
+ </map>
+ <key>VivoxVoicePort</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice port to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>44125</integer>
+ </map>
+ <key>VoiceCallsFriendsOnly</key>
+ <map>
+ <key>Comment</key>
+ <string>Only accept voice calls from residents on your friends list</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceCallsRejectAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Silently reject all incoming voice calls.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceDisableMic</key>
+ <map>
+ <key>Comment</key>
+ <string>Completely disable the ability to open the mic.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceEffectExpiryWarningTime</key>
+ <map>
+ <key>Comment</key>
+ <string>How much notice to give of Voice Morph subscriptions expiry, in seconds.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>259200</integer>
+ </map>
+ <key>VoiceMorphingEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to enable Voice Morphs and show the UI.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AutoDisengageMic</key>
+ <map>
+ <key>Comment</key>
+ <string>Automatically turn off the microphone when ending IM calls.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VoiceEarLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Location of the virtual ear for voice</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceHost</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice host to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>127.0.0.1</string>
+ </map>
+ <key>VoiceImageLevel0</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 0</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>041ee5a0-cb6a-9ac5-6e49-41e9320507d5</string>
+ </map>
+ <key>VoiceImageLevel1</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 1</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceImageLevel2</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 2</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceImageLevel3</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 3</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceImageLevel4</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 4</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceImageLevel5</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 5</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceImageLevel6</key>
+ <map>
+ <key>Comment</key>
+ <string>Texture UUID for voice image level 6</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>29de489d-0491-fb00-7dab-f9e686d31e83</string>
+ </map>
+ <key>VoiceInputAudioDevice</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio input device to use for voice</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Default</string>
+ </map>
+ <key>VoiceLogFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Log file to use when launching the voice daemon</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>VoiceOutputAudioDevice</key>
+ <map>
+ <key>Comment</key>
+ <string>Audio output device to use for voice</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>Default</string>
+ </map>
+ <key>VoiceParticipantLeftRemoveDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout to remove participants who has left Voice chat from the list in Voice Controls Panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>VoicePort</key>
+ <map>
+ <key>Comment</key>
+ <string>Client SLVoice port to connect to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>44125</integer>
+ </map>
+ <key>WarningsAsChat</key>
+ <map>
+ <key>Comment</key>
+ <string>Display warning messages in chat history</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceServerType</key>
+ <map>
+ <key>Comment</key>
+ <string>The type of voice server to connect to.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>vivox</string>
+ </map>
+ <key>WLSkyDetail</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls vertex detail on the WindLight sky. Lower numbers will give better performance and uglier skies.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>64</integer>
+ </map>
+ <key>WatchdogEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls whether the thread watchdog timer is activated.</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>WaterEditPresets</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to be able to edit the water defaults or not</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>WaterFogColor</key>
+ <map>
+ <key>Comment</key>
+ <string>Water fog color</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Color4</string>
+ <key>Value</key>
+ <array>
+ <real>0.0863</real>
+ <real>0.168</real>
+ <real>0.212</real>
+ <real>0</real>
+ </array>
+ </map>
+ <key>WaterFogDensity</key>
+ <map>
+ <key>Comment</key>
+ <string>Water fog density</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16.0</real>
+ </map>
+ <key>WaterGLFogDensityScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Maps shader water fog density to gl fog density</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.02</real>
+ </map>
+ <key>WaterGLFogDepthFloor</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls how dark water gl fog can get</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>WaterGLFogDepthScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls how quickly gl fog gets dark under water</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>50.0</real>
+ </map>
+ <key>WellIconFlashCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of flashes of IM Well and Notification Well icons after which flashing buttons stay lit up. Requires restart.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>3</integer>
+ </map>
+ <key>WellIconFlashPeriod</key>
+ <map>
+ <key>Comment</key>
+ <string>Period at which IM Well and Notification Well icons flash (seconds). Requires restart.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.25</real>
+ </map>
+ <key>WindLightUseAtmosShaders</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether to enable or disable WindLight atmospheric shaders.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>WindowFullScreen</key>
+ <map>
+ <key>Comment</key>
+ <string>SL viewer window full screen</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>WindowHeight</key>
+ <map>
+ <key>Comment</key>
+ <string>SL viewer window height</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>738</integer>
+ </map>
+ <key>WindowMaximized</key>
+ <map>
+ <key>Comment</key>
+ <string>SL viewer window maximized on login</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>WindowWidth</key>
+ <map>
+ <key>Comment</key>
+ <string>SL viewer window width</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1024</integer>
+ </map>
+ <key>WindowX</key>
+ <map>
+ <key>Comment</key>
+ <string>X coordinate of lower left corner of SL viewer window, relative to primary display (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>WindowY</key>
+ <map>
+ <key>Comment</key>
+ <string>Y coordinate of lower left corner of SL viewer window, relative to primary display (pixels)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>XferThrottle</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum allowable downstream bandwidth for asset transfers (bits per second)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>150000.0</real>
+ </map>
+ <key>ExternalEditor</key>
+ <map>
+ <key>Comment</key>
+ <string>Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s"</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>YawFromMousePosition</key>
+ <map>
+ <key>Comment</key>
+ <string>Horizontal range over which avatar head tracks mouse position (degrees of head rotation from left of window to right)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>90.0</real>
+ </map>
+ <key>YouAreHereDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Radius of distance for banner that indicates if the resident is "on" the Place.(meters from avatar to requested place)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10.0</real>
+ </map>
+ <key>YieldTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Yield some time to the local host.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
+ <key>ZoomDirect</key>
+ <map>
+ <key>Comment</key>
+ <string>Map Joystick zoom axis directly to camera zoom.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ZoomTime</key>
+ <map>
+ <key>Comment</key>
+ <string>Time of transition between different camera modes (seconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.40000000596</real>
+ </map>
+ <key>moapbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight media on a prim sources</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>particlesbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight particle generators</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>physicalbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight physical objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>renderbeacons</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight particle generators</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>renderhighlights</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight scripted objects with touch function</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>scriptsbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight scripted objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>scripttouchbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight scripted objects with touch function</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowDeviceSettings</key>
+ <map>
+ <key>Comment</key>
+ <string>Show device settings</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SLURLDragNDrop</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable drag and drop of SLURLs onto the viewer</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>soundsbeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Beacon / Highlight sound generators</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LogTextureDownloadsToViewerLog</key>
+ <map>
+ <key>Comment</key>
+ <string>Send texture download details to the viewer log</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LogTextureDownloadsToSimulator</key>
+ <map>
+ <key>Comment</key>
+ <string>Send a digest of texture info to the sim</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>TextureLoggingThreshold</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies the byte threshold at which texture download data should be sent to the sim.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+
+ <!-- Settings below are for back compatibility only.
+ They are not used in current viewer anymore. But they can't be removed to avoid
+ influence on previous versions of the viewer in case of settings are not used or default value
+ should be changed. See also EXT-6661. -->
+ <!-- 1.23 settings -->
+ <key>ShowVoiceChannelPopup</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls visibility of the current voice channel popup above the voice tab</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowVolumeSettingsPopup</key>
+ <map>
+ <key>Comment</key>
+ <string>Show individual volume slider for voice, sound effects, etc</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>max_texture_dimension_X</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum texture width for user uploaded textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2048</integer>
+ </map>
+ <key>max_texture_dimension_Y</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum texture height for user uploaded textures</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2048</integer>
+ </map>
+ <!-- End of back compatibility settings -->
+ <key>teleport_offer_invitation_max_length</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum length of teleport offer invitation line editor. 254 - max_location_url_length(76) = 178</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>178</integer>
+ </map>
+ <key>always_showable_floaters</key>
+ <map>
+ <key>Comment</key>
+ <string>Floaters that can be shown despite mouselook mode</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>LLSD</string>
+ <key>Value</key>
+ <array>
+ <string>snapshot</string>
+ <string>postcard</string>
+ <string>mini_map</string>
+ </array>
+ </map>
+ <key>LandmarksSortedByDate</key>
+ <map>
+ <key>Comment</key>
+ <string>Reflects landmarks panel sorting order.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>OutfitOperationsTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Timeout for outfit related operations.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>180</integer>
+ </map>
+ <key>HeightUnits</key>
+ <map>
+ <key>Comment</key>
+ <string>Determines which metric units are used: 1(TRUE) for meter and 0(FALSE) for foot.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>TipToastMessageLineCount</key>
+ <map>
+ <key>Comment</key>
+ <string>Max line count of text message on tip toast.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>10</integer>
+ </map>
+ <key>NotMovingHintTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds to wait for resident to move before displaying move hint.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>120.0</real>
+ </map>
+ <key>DestinationGuideHintTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds to wait before telling resident about destination guide.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>1200.0</real>
+ </map>
+ <key>SidePanelHintTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds to wait before telling resident about side panel.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>300.0</real>
+ </map>
+ <key>GroupMembersSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>The order by which group members will be sorted (name|donated|online)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>name</string>
+ </map>
+ <key>SessionSettingsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>Settings that are a applied per session (not saved).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string></string>
+ </map>
+ <key>UserSessionSettingsFile</key>
+ <map>
+ <key>Comment</key>
+ <string>User settings that are a applied per session (not saved).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string />
+ </map>
+ <key>OpenSidePanelsInFloaters</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, will always open side panel contents in a floater.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AvatarInspectorTooltipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying avatar inspector tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.35</real>
+ </map>
+ <key>ObjectInspectorTooltipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying object inspector tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.35</real>
+ </map>
+ <key>SLURLTeleportDirectly</key>
+ <map>
+ <key>Comment</key>
+ <string>Clicking on a slurl will teleport you directly instead of opening places panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable creation of new classified ads from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableGroupInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing and editing of group info from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnablePicks</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable editing of picks from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening world map from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAvatarPay</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable paying other avatars from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableVoiceCall</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable voice calls from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAvatarShare</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable sharing from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SearchFromAddressBar</key>
+ <map>
+ <key>Comment</key>
+ <string>Can enter search queries into navigation address bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LogInventoryDecline</key>
+ <map>
+ <key>Comment</key>
+ <string>Log in system chat whenever an inventory offer is declined</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseHTTPInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow use of http inventory transfers instead of UDP</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ClickToWalk</key>
+ <map>
+ <key>Comment</key>
+ <string>Click in world to walk to location</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowOfferedInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Show inventory window with last inventory offer selected when receiving inventory from other users.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>GenericErrorPageURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL to set as a property on LLMediaControl to navigate to if the a page completes with a 400-499 HTTP status code</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/404.html</string>
+ </map>
+ <key>DestinationsAndAvatarsVisibility</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether destination panel or avatar picker are open (0=destination guide, 1=avatar picker, default=nothing)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+</map>
+</llsd>
diff --git a/indra/newview/app_settings/settings_minimal.xml b/indra/newview/app_settings/settings_minimal.xml
index 03656f2a53..490da2c9d4 100644
--- a/indra/newview/app_settings/settings_minimal.xml
+++ b/indra/newview/app_settings/settings_minimal.xml
@@ -61,7 +61,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/howto/index.html?topic=[TOPIC]</string>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/howto/index.html?topic=[TOPIC]</string>
</map>
<key>PreferredMaturity</key>
<map>
@@ -345,7 +345,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/guide.html</string>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/guide.html</string>
</map>
<key>AvatarPickerURL</key>
<map>
@@ -356,7 +356,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/avatars.html</string>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/avatars.html</string>
</map>
<key>LogInventoryDecline</key>
<map>
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index 85899603ee..ec162e3608 100644
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -4339,8 +4339,8 @@
wearable="shape"
edit_group="driven"
value_default="0"
- value_min="-2"
- value_max="2">
+ value_min="-3"
+ value_max="3">
<param_morph />
</param>
@@ -4352,8 +4352,8 @@
wearable="shape"
edit_group="driven"
value_default="0"
- value_min="-1"
- value_max="1">
+ value_min="-1.5"
+ value_max="1.5">
<param_morph />
</param>
@@ -11916,7 +11916,7 @@ render_pass="bump">
edit_group="physics_breasts_updown"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
@@ -11971,7 +11971,7 @@ render_pass="bump">
edit_group="physics_breasts_inout"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
@@ -12058,7 +12058,7 @@ render_pass="bump">
edit_group="physics_belly_updown"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
@@ -12144,7 +12144,7 @@ render_pass="bump">
edit_group="physics_butt_updown"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
@@ -12193,7 +12193,7 @@ render_pass="bump">
edit_group="physics_butt_leftright"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
@@ -12244,7 +12244,7 @@ render_pass="bump">
edit_group="physics_breasts_leftright"
value_default=".1"
value_min="0"
- value_max="1">
+ value_max="3">
<param_driver />
</param>
<param
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 3f1bf4c5c2..790f98e75d 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1119,12 +1119,6 @@ void LLAgent::resetControlFlags()
//-----------------------------------------------------------------------------
void LLAgent::setAFK()
{
- // Drones can't go AFK
- if (gNoRender)
- {
- return;
- }
-
if (!gAgent.getRegion())
{
// Don't set AFK if we're not talking to a region yet.
@@ -1690,11 +1684,6 @@ void LLAgent::clearRenderState(U8 clearstate)
//-----------------------------------------------------------------------------
U8 LLAgent::getRenderState()
{
- if (gNoRender || gKeyboard == NULL)
- {
- return 0;
- }
-
// *FIX: don't do stuff in a getter! This is infinite loop city!
if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS)
&& (mRenderState & AGENT_STATE_TYPING))
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index f5fd33d5e0..c6b5a0113f 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -282,25 +282,22 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
gAgent.stopAutoPilot(TRUE);
}
- if (!gNoRender)
- {
- LLSelectMgr::getInstance()->unhighlightAll();
+ LLSelectMgr::getInstance()->unhighlightAll();
- // By popular request, keep land selection while walking around. JC
- // LLViewerParcelMgr::getInstance()->deselectLand();
+ // By popular request, keep land selection while walking around. JC
+ // LLViewerParcelMgr::getInstance()->deselectLand();
- // force deselect when walking and attachment is selected
- // this is so people don't wig out when their avatar moves without animating
- if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
- {
- LLSelectMgr::getInstance()->deselectAll();
- }
+ // force deselect when walking and attachment is selected
+ // this is so people don't wig out when their avatar moves without animating
+ if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ }
- if (gMenuHolder != NULL)
- {
- // Hide all popup menus
- gMenuHolder->hideMenus();
- }
+ if (gMenuHolder != NULL)
+ {
+ // Hide all popup menus
+ gMenuHolder->hideMenus();
}
if (change_camera && !gSavedSettings.getBOOL("FreezeTime"))
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index d520debc31..ed24febf41 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -37,6 +37,8 @@
#include "llviewerobject.h"
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
+#include "llsdutil.h"
+#include "llsdutil_math.h"
LLAgentListener::LLAgentListener(LLAgent &agent)
: LLEventAPI("LLAgent",
@@ -53,6 +55,15 @@ LLAgentListener::LLAgentListener(LLAgent &agent)
add("requestStand",
"Ask to stand up",
&LLAgentListener::requestStand);
+ add("resetAxes",
+ "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",
+ &LLAgentListener::resetAxes);
+ add("getAxes",
+ "Send information about the agent's orientation on [\"reply\"]:\n"
+ "[\"euler\"]: map of {roll, pitch, yaw}\n"
+ "[\"quat\"]: array of [x, y, z, w] quaternion values",
+ &LLAgentListener::getAxes,
+ LLSDMap("reply", LLSD()));
}
void LLAgentListener::requestTeleport(LLSD const & event_data) const
@@ -64,7 +75,7 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const
params.append(event_data["x"]);
params.append(event_data["y"]);
params.append(event_data["z"]);
- LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, true);
+ LLCommandDispatcher::dispatch("teleport", params, LLSD(), NULL, "clicked", true);
// *TODO - lookup other LLCommandHandlers for "agent", "classified", "event", "group", "floater", "parcel", "login", login_refresh", "balance", "chat"
// should we just compose LLCommandHandler and LLDispatchListener?
}
@@ -74,7 +85,7 @@ void LLAgentListener::requestTeleport(LLSD const & event_data) const
LLVector3(event_data["x"].asReal(),
event_data["y"].asReal(),
event_data["z"].asReal())).getSLURLString();
- LLURLDispatcher::dispatch(url, NULL, false);
+ LLURLDispatcher::dispatch(url, "clicked", NULL, false);
}
}
@@ -104,3 +115,28 @@ void LLAgentListener::requestStand(LLSD const & event_data) const
mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
}
+void LLAgentListener::resetAxes(const LLSD& event) const
+{
+ if (event.has("lookat"))
+ {
+ mAgent.resetAxes(ll_vector3_from_sd(event["lookat"]));
+ }
+ else
+ {
+ // no "lookat", default call
+ mAgent.resetAxes();
+ }
+}
+
+void LLAgentListener::getAxes(const LLSD& event) const
+{
+ LLQuaternion quat(mAgent.getQuat());
+ F32 roll, pitch, yaw;
+ quat.getEulerAngles(&roll, &pitch, &yaw);
+ // The official query API for LLQuaternion's [x, y, z, w] values is its
+ // public member mQ...
+ sendReply(LLSDMap
+ ("quat", llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ)))
+ ("euler", LLSDMap("roll", roll)("pitch", pitch)("yaw", yaw)),
+ event);
+}
diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h
index 9b585152f4..0aa58d0b16 100644
--- a/indra/newview/llagentlistener.h
+++ b/indra/newview/llagentlistener.h
@@ -44,6 +44,8 @@ private:
void requestTeleport(LLSD const & event_data) const;
void requestSit(LLSD const & event_data) const;
void requestStand(LLSD const & event_data) const;
+ void resetAxes(const LLSD& event) const;
+ void getAxes(const LLSD& event) const;
private:
LLAgent & mAgent;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 643c611b30..5dc803e287 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -81,7 +81,6 @@
#include "llvoicechannel.h"
#include "llvoavatarself.h"
#include "llsidetray.h"
-#include "llfeaturemanager.h"
#include "llurlmatch.h"
#include "lltextutil.h"
#include "lllogininstance.h"
@@ -761,7 +760,7 @@ bool LLAppViewer::init()
//
// Various introspection concerning the libs we're using - particularly
- // the libs involved in getting to a full login screen.
+ // the libs involved in getting to a full login screen.
//
LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
@@ -930,7 +929,7 @@ bool LLAppViewer::init()
}
// If we don't have the right GL requirements, exit.
- if (!gGLManager.mHasRequirements && !gNoRender)
+ if (!gGLManager.mHasRequirements)
{
// can't use an alert here since we're exiting and
// all hell breaks lose.
@@ -1232,7 +1231,8 @@ bool LLAppViewer::mainLoop()
}
// Render scene.
- if (!LLApp::isExiting())
+ // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
+ if (!LLApp::isExiting() && !gHeadlessClient)
{
pingMainloopTimeout("Main:Display");
gGLActive = TRUE;
@@ -1260,8 +1260,7 @@ bool LLAppViewer::mainLoop()
}
// yield cooperatively when not running as foreground window
- if ( gNoRender
- || (gViewerWindow && !gViewerWindow->mWindow->getVisible())
+ if ( (gViewerWindow && !gViewerWindow->mWindow->getVisible())
|| !gFocusMgr.getAppHasFocus())
{
// Sleep if we're not rendering, or the window is minimized.
@@ -2512,6 +2511,14 @@ bool LLAppViewer::initConfiguration()
}
}
+ // If automatic login from command line with --login switch
+ // init StartSLURL location. In interactive login, LLPanelLogin
+ // will take care of it.
+ if ((clp.hasOption("login") || clp.hasOption("autologin")) && !clp.hasOption("url") && !clp.hasOption("slurl"))
+ {
+ LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
+ }
+
if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
{
//
@@ -2776,12 +2783,26 @@ void LLAppViewer::checkForCrash(void)
}
+//
+// This function decides whether the client machine meets the minimum requirements to
+// run in a maximized window, per the consensus of davep, boa and nyx on 3/30/2011.
+//
+bool LLAppViewer::meetsRequirementsForMaximizedStart()
+{
+ bool maximizedOk = (LLFeatureManager::getInstance()->getGPUClass() >= GPU_CLASS_2);
+
+ const U32 one_gigabyte_kb = 1024 * 1024;
+ maximizedOk &= (gSysMemory.getPhysicalMemoryKB() >= one_gigabyte_kb);
+
+ return maximizedOk;
+}
+
bool LLAppViewer::initWindow()
{
LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
// store setting in a global for easy access and modification
- gNoRender = gSavedSettings.getBOOL("DisableRendering");
+ gHeadlessClient = gSavedSettings.getBOOL("HeadlessClient");
// always start windowed
BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
@@ -2795,7 +2816,8 @@ bool LLAppViewer::initWindow()
const S32 NEVER_SUBMIT_REPORT = 2;
bool use_watchdog = false;
int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
- if(watchdog_enabled_setting == -1){
+ if(watchdog_enabled_setting == -1)
+ {
use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
}
else
@@ -2817,29 +2839,26 @@ bool LLAppViewer::initWindow()
gViewerWindow->mWindow->maximize();
}
- if (!gNoRender)
+ //
+ // Initialize GL stuff
+ //
+
+ if (mForceGraphicsDetail)
{
- //
- // Initialize GL stuff
- //
+ LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false);
+ }
+
+ // Set this flag in case we crash while initializing GL
+ gSavedSettings.setBOOL("RenderInitError", TRUE);
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
- if (mForceGraphicsDetail)
- {
- LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false);
- }
-
- // Set this flag in case we crash while initializing GL
- gSavedSettings.setBOOL("RenderInitError", TRUE);
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
-
- gPipeline.init();
+ gPipeline.init();
- stop_glerror();
- gViewerWindow->initGLDefaults();
+ stop_glerror();
+ gViewerWindow->initGLDefaults();
- gSavedSettings.setBOOL("RenderInitError", FALSE);
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
- }
+ gSavedSettings.setBOOL("RenderInitError", FALSE);
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
//If we have a startup crash, it's usually near GL initialization, so simulate that.
if(gCrashOnStartup)
@@ -2847,6 +2866,21 @@ bool LLAppViewer::initWindow()
LLAppViewer::instance()->forceErrorLLError();
}
+ //
+ // Determine if the window should start maximized on initial run based
+ // on graphics capability
+ //
+ if (gSavedSettings.getBOOL("FirstLoginThisInstall") && meetsRequirementsForMaximizedStart())
+ {
+ LL_INFOS("AppInit") << "This client met the requirements for a maximized initial screen." << LL_ENDL;
+ gSavedSettings.setBOOL("WindowMaximized", TRUE);
+ }
+
+ if (gSavedSettings.getBOOL("WindowMaximized"))
+ {
+ gViewerWindow->mWindow->maximize();
+ }
+
LLUI::sWindow = gViewerWindow->getWindow();
// Show watch cursor
@@ -2881,12 +2915,9 @@ void LLAppViewer::cleanupSavedSettings()
gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
- if (!gNoRender)
+ if (gDebugView)
{
- if (gDebugView)
- {
- gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
- }
+ gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
}
// save window position if not maximized
@@ -3869,7 +3900,7 @@ void LLAppViewer::badNetworkHandler()
// is destroyed.
void LLAppViewer::saveFinalSnapshot()
{
- if (!mSavedFinalSnapshot && !gNoRender)
+ if (!mSavedFinalSnapshot)
{
gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal());
gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal());
@@ -4277,34 +4308,31 @@ void LLAppViewer::idle()
//
// Update weather effects
//
- if (!gNoRender)
- {
- LLWorld::getInstance()->updateClouds(gFrameDTClamped);
- gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets
+ LLWorld::getInstance()->updateClouds(gFrameDTClamped);
+ gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets
- // Update wind vector
- LLVector3 wind_position_region;
- static LLVector3 average_wind;
+ // Update wind vector
+ LLVector3 wind_position_region;
+ static LLVector3 average_wind;
- LLViewerRegion *regionp;
- regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position
- if (regionp)
- {
- gWindVec = regionp->mWind.getVelocity(wind_position_region);
+ LLViewerRegion *regionp;
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position
+ if (regionp)
+ {
+ gWindVec = regionp->mWind.getVelocity(wind_position_region);
- // Compute average wind and use to drive motion of water
-
- average_wind = regionp->mWind.getAverage();
- F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
-
- gSky.setCloudDensityAtAgent(cloud_density);
- gSky.setWind(average_wind);
- //LLVOWater::setWind(average_wind);
- }
- else
- {
- gWindVec.setVec(0.0f, 0.0f, 0.0f);
- }
+ // Compute average wind and use to drive motion of water
+
+ average_wind = regionp->mWind.getAverage();
+ F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
+
+ gSky.setCloudDensityAtAgent(cloud_density);
+ gSky.setWind(average_wind);
+ //LLVOWater::setWind(average_wind);
+ }
+ else
+ {
+ gWindVec.setVec(0.0f, 0.0f, 0.0f);
}
//////////////////////////////////////
@@ -4313,13 +4341,10 @@ void LLAppViewer::idle()
// Here, particles are updated and drawables are moved.
//
- if (!gNoRender)
- {
- LLFastTimer t(FTM_WORLD_UPDATE);
- gPipeline.updateMove();
+ LLFastTimer t(FTM_WORLD_UPDATE);
+ gPipeline.updateMove();
- LLWorld::getInstance()->updateParticles();
- }
+ LLWorld::getInstance()->updateParticles();
if (gAgentPilot.isPlaying() && gAgentPilot.getOverrideCamera())
{
@@ -4694,12 +4719,9 @@ void LLAppViewer::disconnectViewer()
gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
// Un-minimize all windows so they don't get saved minimized
- if (!gNoRender)
+ if (gFloaterView)
{
- if (gFloaterView)
- {
- gFloaterView->restoreAll();
- }
+ gFloaterView->restoreAll();
}
if (LLSelectMgr::getInstance())
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 0226211735..61ee6a7cf1 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -187,6 +187,7 @@ protected:
virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this.
+ virtual bool meetsRequirementsForMaximizedStart(); // Used on first login to decide to launch maximized
private:
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 898cc1c0ba..523c2e3adf 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -233,7 +233,7 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ
std::string url = slurl;
LLMediaCtrl* web = NULL;
const bool trusted_browser = false;
- if (LLURLDispatcher::dispatch(url, web, trusted_browser))
+ if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
{
// bring window to foreground, as it has just been "launched" from a URL
// todo: hmm, how to get there from here?
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index 1cd80986d8..c2916717bd 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -500,7 +500,7 @@ OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
LLMediaCtrl* web = NULL;
const bool trusted_browser = false;
- LLURLDispatcher::dispatch(url, web, trusted_browser);
+ LLURLDispatcher::dispatch(url, "", web, trusted_browser);
}
return(result);
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index afa8b62c74..ca7ec7cc30 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -279,7 +279,7 @@ bool LLAvatarActions::isCalling(const LLUUID &id)
//static
bool LLAvatarActions::canCall()
{
- return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
+ return LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
}
// static
@@ -300,40 +300,21 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids)
make_ui_sound("UISndStartIM");
}
+static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ llinfos << "opening web profile for " << av_name.mUsername << llendl;
+ std::string url = getProfileURL(av_name.mUsername);
+
+ // PROFILES: open in webkit window
+ LLWeb::loadWebURLInternal(url, "", agent_id.asString());
+}
+
// static
void LLAvatarActions::showProfile(const LLUUID& id)
{
if (id.notNull())
{
- LLSD params;
- params["id"] = id;
- params["open_tab_name"] = "panel_profile";
-
- // PROFILES: open in webkit window
- std::string full_name;
- if (gCacheName->getFullName(id,full_name))
- {
- std::string agent_name = LLCacheName::buildUsername(full_name);
- llinfos << "opening web profile for " << agent_name << llendl;
- std::string url = getProfileURL(agent_name);
- LLWeb::loadWebURLInternal(url, "", id.asString());
- }
- else
- {
- llwarns << "no name info for agent id " << id << llendl;
- }
-#if 0
- //Show own profile
- if(gAgent.getID() == id)
- {
- LLSideTray::getInstance()->showPanel("panel_me", params);
- }
- //Show other user profile
- else
- {
- LLSideTray::getInstance()->showPanel("panel_profile_view", params);
- }
-#endif
+ LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2));
}
}
diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp
index 99aeb4cbad..b1cd83a1fb 100644
--- a/indra/newview/llavatarpropertiesprocessor.cpp
+++ b/indra/newview/llavatarpropertiesprocessor.cpp
@@ -160,6 +160,12 @@ void LLAvatarPropertiesProcessor::sendAvatarClassifiedsRequest(const LLUUID& ava
void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props)
{
+ if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null))
+ {
+ llwarns << "Sending avatarinfo update DENIED - invalid agent" << llendl;
+ return;
+ }
+
llinfos << "Sending avatarinfo update" << llendl;
// This value is required by sendAvatarPropertiesUpdate method.
@@ -168,20 +174,21 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData*
LLMessageSystem *msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- msg->nextBlockFast(_PREHASH_PropertiesData);
+ msg->newMessageFast (_PREHASH_AvatarPropertiesUpdate);
+ msg->nextBlockFast (_PREHASH_AgentData);
+ msg->addUUIDFast (_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast (_PREHASH_SessionID, gAgent.getSessionID() );
+ msg->nextBlockFast (_PREHASH_PropertiesData);
- msg->addUUIDFast( _PREHASH_ImageID, avatar_props->image_id);
- msg->addUUIDFast( _PREHASH_FLImageID, avatar_props->fl_image_id);
- msg->addStringFast( _PREHASH_AboutText, avatar_props->about_text);
- msg->addStringFast( _PREHASH_FLAboutText, avatar_props->fl_about_text);
+ msg->addUUIDFast (_PREHASH_ImageID, avatar_props->image_id);
+ msg->addUUIDFast (_PREHASH_FLImageID, avatar_props->fl_image_id);
+ msg->addStringFast (_PREHASH_AboutText, avatar_props->about_text);
+ msg->addStringFast (_PREHASH_FLAboutText, avatar_props->fl_about_text);
msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish);
msg->addBOOL(_PREHASH_MaturePublish, mature);
msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url);
+
gAgent.sendReliableMessage();
}
diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp
index 7c205a8b9f..9a8cd5ceae 100644
--- a/indra/newview/llbreastmotion.cpp
+++ b/indra/newview/llbreastmotion.cpp
@@ -2,31 +2,25 @@
* @file llbreastmotion.cpp
* @brief Implementation of LLBreastMotion class.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
* 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
+ * Copyright (C) 2011, 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.
*
- * 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
+ * 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/newview/llbreastmotion.h b/indra/newview/llbreastmotion.h
index 8578d4ad1a..aa0fdf9f8b 100644
--- a/indra/newview/llbreastmotion.h
+++ b/indra/newview/llbreastmotion.h
@@ -2,31 +2,25 @@
* @file llbreastmotion.h
* @brief Implementation of LLBreastMotion class.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
* 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
+ * Copyright (C) 2011, 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.
*
- * 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
+ * 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/newview/llcommanddispatcherlistener.cpp b/indra/newview/llcommanddispatcherlistener.cpp
index 5744d055a9..586f45fd8f 100644
--- a/indra/newview/llcommanddispatcherlistener.cpp
+++ b/indra/newview/llcommanddispatcherlistener.cpp
@@ -65,7 +65,7 @@ void LLCommandDispatcherListener::dispatch(const LLSD& params) const
trusted_browser = params["trusted"].asBoolean();
}
LLCommandDispatcher::dispatch(params["cmd"], params["params"], params["query"], NULL,
- trusted_browser);
+ "clicked", trusted_browser);
}
void LLCommandDispatcherListener::enumerate(const LLSD& params) const
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 1b6ba02aac..19dba3f917 100644
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -35,7 +35,7 @@
// system includes
#include <boost/tokenizer.hpp>
-#define THROTTLE_PERIOD 5 // required secs between throttled commands
+#define THROTTLE_PERIOD 5 // required seconds between throttled commands
static LLCommandDispatcherListener sCommandDispatcherListener;
@@ -59,6 +59,7 @@ public:
const LLSD& params,
const LLSD& query_map,
LLMediaCtrl* web,
+ const std::string& nav_type,
bool trusted_browser);
private:
@@ -91,6 +92,7 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
const LLSD& params,
const LLSD& query_map,
LLMediaCtrl* web,
+ const std::string& nav_type,
bool trusted_browser)
{
static bool slurl_blocked = false;
@@ -120,11 +122,19 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
return true;
case LLCommandHandler::UNTRUSTED_THROTTLE:
+ // if users actually click on a link, we don't need to throttle it
+ // (throttling mechanism is used to prevent an avalanche of clicks via
+ // javascript
+ if ( nav_type == "clicked" )
+ {
+ break;
+ }
+
cur_time = LLTimer::getElapsedSeconds();
if (cur_time < last_throttle_time + THROTTLE_PERIOD)
{
// block request from external browser if it happened
- // within THROTTLE_PERIOD secs of the last command
+ // within THROTTLE_PERIOD seconds of the last command
LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL;
if (! slurl_throttled)
{
@@ -166,10 +176,11 @@ bool LLCommandDispatcher::dispatch(const std::string& cmd,
const LLSD& params,
const LLSD& query_map,
LLMediaCtrl* web,
+ const std::string& nav_type,
bool trusted_browser)
{
return LLCommandHandlerRegistry::instance().dispatch(
- cmd, params, query_map, web, trusted_browser);
+ cmd, params, query_map, web, nav_type, trusted_browser);
}
static std::string lookup(LLCommandHandler::EUntrustedAccess value);
diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h
index 1e65b6de23..1e0895565a 100644
--- a/indra/newview/llcommandhandler.h
+++ b/indra/newview/llcommandhandler.h
@@ -95,6 +95,7 @@ public:
const LLSD& params,
const LLSD& query_map,
LLMediaCtrl* web,
+ const std::string& nav_type,
bool trusted_browser);
// Execute a command registered via the above mechanism,
// passing string parameters.
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 5e10f60aba..5501b8c2ac 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -123,10 +123,7 @@ void LLExpandableTextBox::LLTextBoxEx::reshape(S32 width, S32 height, BOOL calle
{
LLTextEditor::reshape(width, height, called_from_parent);
- if (getTextPixelHeight() > getRect().getHeight())
- {
- showExpandText();
- }
+ hideOrShowExpandTextAsNeeded();
}
void LLExpandableTextBox::LLTextBoxEx::setText(const LLStringExplicit& text,const LLStyle::Params& input_params)
@@ -136,17 +133,7 @@ void LLExpandableTextBox::LLTextBoxEx::setText(const LLStringExplicit& text,cons
mExpanderVisible = false;
LLTextEditor::setText(text, input_params);
- // text contents have changed, segments are cleared out
- // so hide the expander and determine if we need it
- //mExpanderVisible = false;
- if (getTextPixelHeight() > getRect().getHeight())
- {
- showExpandText();
- }
- else
- {
- hideExpandText();
- }
+ hideOrShowExpandTextAsNeeded();
}
@@ -200,6 +187,22 @@ S32 LLExpandableTextBox::LLTextBoxEx::getTextPixelHeight()
return getTextBoundingRect().getHeight();
}
+void LLExpandableTextBox::LLTextBoxEx::hideOrShowExpandTextAsNeeded()
+{
+ // Restore the text box contents to calculate the text height properly,
+ // otherwise if a part of the text is hidden under "More" link
+ // getTextPixelHeight() returns only the height of currently visible text
+ // including the "More" link. See STORM-250.
+ hideExpandText();
+
+ // Show the expander a.k.a. "More" link if we need it, depending on text
+ // contents height. If not, keep it hidden.
+ if (getTextPixelHeight() > getRect().getHeight())
+ {
+ showExpandText();
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llexpandabletextbox.h b/indra/newview/llexpandabletextbox.h
index bce77225c4..f75ef954ff 100644
--- a/indra/newview/llexpandabletextbox.h
+++ b/indra/newview/llexpandabletextbox.h
@@ -77,6 +77,12 @@ protected:
*/
void hideExpandText();
+ /**
+ * Shows the "More" link if the text is too high to be completely
+ * visible without expanding the text box. Hides that link otherwise.
+ */
+ void hideOrShowExpandTextAsNeeded();
+
protected:
LLTextBoxEx(const Params& p);
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index d63685e1af..2c4153688a 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -121,7 +121,11 @@ void LLFirstUse::notMoving(bool enable)
{
// fire off 2 notifications and rely on filtering to select the relevant one
firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
- firstUseNotification("FirstNotMoving", enable, "HintMoveArrows", LLSD(), LLSD().with("target", "bottom_tray").with("direction", "top").with("hint_image", "arrow_keys.png").with("down_arrow", ""));
+ firstUseNotification("FirstNotMoving", enable, "HintMoveClick", LLSD(), LLSD()
+ .with("target", "nav_bar")
+ .with("direction", "bottom")
+ .with("hint_image", "click_to_move.png")
+ .with("up_arrow", ""));
}
// static
diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp
index 61cf4dad93..eeb81085bb 100644
--- a/indra/newview/llfloaterbump.cpp
+++ b/indra/newview/llfloaterbump.cpp
@@ -38,13 +38,11 @@
///----------------------------------------------------------------------------
/// Class LLFloaterBump
///----------------------------------------------------------------------------
-extern BOOL gNoRender;
// Default constructor
LLFloaterBump::LLFloaterBump(const LLSD& key)
: LLFloater(key)
{
- if(gNoRender) return;
}
diff --git a/indra/newview/llfloaterhelpbrowser.cpp b/indra/newview/llfloaterhelpbrowser.cpp
index a650886d89..627defd006 100644
--- a/indra/newview/llfloaterhelpbrowser.cpp
+++ b/indra/newview/llfloaterhelpbrowser.cpp
@@ -50,6 +50,7 @@ BOOL LLFloaterHelpBrowser::postBuild()
{
mBrowser = getChild<LLMediaCtrl>("browser");
mBrowser->addObserver(this);
+ mBrowser->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
childSetAction("open_browser", onClickOpenWebBrowser, this);
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index fcf8b084c5..240f5e02fe 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -285,6 +285,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
mGotPersonalInfo(false),
mOriginalIMViaEmail(false),
mLanguageChanged(false),
+ mAvatarDataInitialized(false),
mDoubleClickActionDirty(false),
mFavoritesRecordMayExist(false)
{
@@ -343,7 +344,7 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t
if ( APT_PROPERTIES == type )
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData );
- if( pAvatarData && gAgent.getID() == pAvatarData->avatar_id )
+ if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
{
storeAvatarProperties( pAvatarData );
processProfileProperties( pAvatarData );
@@ -353,14 +354,19 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t
void LLFloaterPreference::storeAvatarProperties( const LLAvatarData* pAvatarData )
{
- mAvatarProperties.avatar_id = gAgent.getID();
- mAvatarProperties.image_id = pAvatarData->image_id;
- mAvatarProperties.fl_image_id = pAvatarData->fl_image_id;
- mAvatarProperties.about_text = pAvatarData->about_text;
- mAvatarProperties.fl_about_text = pAvatarData->fl_about_text;
- mAvatarProperties.profile_url = pAvatarData->profile_url;
- mAvatarProperties.flags = pAvatarData->flags;
- mAvatarProperties.allow_publish = pAvatarData->flags & AVATAR_ALLOW_PUBLISH;
+ if (LLStartUp::getStartupState() == STATE_STARTED)
+ {
+ mAvatarProperties.avatar_id = pAvatarData->avatar_id;
+ mAvatarProperties.image_id = pAvatarData->image_id;
+ mAvatarProperties.fl_image_id = pAvatarData->fl_image_id;
+ mAvatarProperties.about_text = pAvatarData->about_text;
+ mAvatarProperties.fl_about_text = pAvatarData->fl_about_text;
+ mAvatarProperties.profile_url = pAvatarData->profile_url;
+ mAvatarProperties.flags = pAvatarData->flags;
+ mAvatarProperties.allow_publish = pAvatarData->flags & AVATAR_ALLOW_PUBLISH;
+
+ mAvatarDataInitialized = true;
+ }
}
void LLFloaterPreference::processProfileProperties(const LLAvatarData* pAvatarData )
@@ -370,15 +376,31 @@ void LLFloaterPreference::processProfileProperties(const LLAvatarData* pAvatarDa
void LLFloaterPreference::saveAvatarProperties( void )
{
- mAvatarProperties.allow_publish = getChild<LLUICtrl>("online_searchresults")->getValue();
- if ( mAvatarProperties.allow_publish )
+ const BOOL allowPublish = getChild<LLUICtrl>("online_searchresults")->getValue();
+
+ if (allowPublish)
{
mAvatarProperties.flags |= AVATAR_ALLOW_PUBLISH;
}
-
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate( &mAvatarProperties );
-}
+ //
+ // NOTE: We really don't want to send the avatar properties unless we absolutely
+ // need to so we can avoid the accidental profile reset bug, so, if we're
+ // logged in, the avatar data has been initialized and we have a state change
+ // for the "allow publish" flag, then set the flag to its new value and send
+ // the properties update.
+ //
+ // NOTE: The only reason we can not remove this update altogether is because of the
+ // "allow publish" flag, the last remaining profile setting in the viewer
+ // that doesn't exist in the web profile.
+ //
+ if ((LLStartUp::getStartupState() == STATE_STARTED) && mAvatarDataInitialized && (allowPublish != mAvatarProperties.allow_publish))
+ {
+ mAvatarProperties.allow_publish = allowPublish;
+
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate( &mAvatarProperties );
+ }
+}
BOOL LLFloaterPreference::postBuild()
{
@@ -1371,6 +1393,8 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im
mOriginalHideOnlineStatus = true;
}
+ getChild<LLUICtrl>("online_searchresults")->setEnabled(TRUE);
+
getChildView("include_im_in_chat_history")->setEnabled(TRUE);
getChildView("show_timestamps_check_im")->setEnabled(TRUE);
getChildView("friends_online_notify_checkbox")->setEnabled(TRUE);
@@ -1750,7 +1774,6 @@ void LLPanelPreferenceGraphics::draw()
bool enable = hasDirtyChilds();
button_apply->setEnabled(enable);
-
}
}
bool LLPanelPreferenceGraphics::hasDirtyChilds()
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 46014804ec..5d5e066ec5 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -169,6 +169,7 @@ private:
bool mGotPersonalInfo;
bool mOriginalIMViaEmail;
bool mLanguageChanged;
+ bool mAvatarDataInitialized;
bool mOriginalHideOnlineStatus;
// Record of current user's favorites may be stored in file on disk.
diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index c4dcaf11f9..e15862e2a4 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -191,6 +191,8 @@ BOOL LLHintPopup::postBuild()
LLRect text_bounds = hint_text.getTextBoundingRect();
S32 delta_height = text_bounds.getHeight() - hint_text.getRect().getHeight();
reshape(getRect().getWidth(), getRect().getHeight() + delta_height);
+ hint_text.reshape(hint_text.getRect().getWidth(), hint_text.getRect().getHeight() + delta_height);
+// hint_text.translate(0, -delta_height);
return TRUE;
}
@@ -211,6 +213,24 @@ void LLHintPopup::draw()
alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, mFadeInTime, 0.f, 1.f);
}
+ LLIconCtrl* hint_icon = findChild<LLIconCtrl>("hint_image");
+
+ if (hint_icon)
+ {
+ LLUIImagePtr hint_image = hint_icon->getImage();
+ S32 image_height = hint_image.isNull() ? 0 : hint_image->getHeight();
+ S32 image_width = hint_image.isNull() ? 0 : hint_image->getWidth();
+
+ LLView* layout_stack = hint_icon->getParent()->getParent();
+ S32 delta_height = image_height - layout_stack->getRect().getHeight();
+ hint_icon->getParent()->reshape(image_width, hint_icon->getParent()->getRect().getHeight());
+ layout_stack->reshape(layout_stack->getRect().getWidth(), image_height);
+ layout_stack->translate(0, -delta_height);
+
+ LLRect hint_rect = getLocalRect();
+ reshape(hint_rect.getWidth(), hint_rect.getHeight() + delta_height);
+ }
+
{ LLViewDrawContext context(alpha);
if (mTarget.empty())
diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp
index 8cf7d23f88..72f64752d6 100644
--- a/indra/newview/llhudeffectlookat.cpp
+++ b/indra/newview/llhudeffectlookat.cpp
@@ -587,11 +587,6 @@ void LLHUDEffectLookAt::update()
*/
bool LLHUDEffectLookAt::calcTargetPosition()
{
- if (gNoRender)
- {
- return false;
- }
-
LLViewerObject *target_obj = (LLViewerObject *)mTargetObject;
LLVector3 local_offset;
diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp
index 5f3178b955..8f14b53db0 100644
--- a/indra/newview/llhudmanager.cpp
+++ b/indra/newview/llhudmanager.cpp
@@ -38,8 +38,6 @@
#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
-extern BOOL gNoRender;
-
// These are loaded from saved settings.
LLColor4 LLHUDManager::sParentColor;
LLColor4 LLHUDManager::sChildColor;
@@ -150,11 +148,6 @@ LLHUDEffect *LLHUDManager::createViewerEffect(const U8 type, BOOL send_to_sim, B
//static
void LLHUDManager::processViewerEffect(LLMessageSystem *mesgsys, void **user_data)
{
- if (gNoRender)
- {
- return;
- }
-
LLHUDEffect *effectp = NULL;
LLUUID effect_id;
U8 effect_type = 0;
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index f74ae92a7b..50a9c56518 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -56,6 +56,7 @@
#include "llrootview.h"
#include "llspeakers.h"
#include "llsidetray.h"
+#include "llviewerchat.h"
static const S32 RECT_PADDING_NOT_INIT = -1;
@@ -266,7 +267,9 @@ BOOL LLIMFloater::postBuild()
mInputEditor->setMaxTextLength(1023);
// enable line history support for instant message bar
mInputEditor->setEnableLineHistory(TRUE);
-
+
+ LLFontGL* font = LLViewerChat::getChatFont();
+ mInputEditor->setFont(font);
mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) );
mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this) );
@@ -891,6 +894,7 @@ void LLIMFloater::updateChatHistoryStyle()
void LLIMFloater::processChatHistoryStyleUpdate(const LLSD& newvalue)
{
+ LLFontGL* font = LLViewerChat::getChatFont();
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel");
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin();
iter != inst_list.end(); ++iter)
@@ -899,6 +903,7 @@ void LLIMFloater::processChatHistoryStyleUpdate(const LLSD& newvalue)
if (floater)
{
floater->updateChatHistoryStyle();
+ floater->mInputEditor->setFont(font);
}
}
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 0ef502b81b..ec3fe48151 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -3183,10 +3183,6 @@ public:
//just like a normal IM
//this is just replicated code from process_improved_im
//and should really go in it's own function -jwolk
- if (gNoRender)
- {
- return;
- }
LLChat chat;
std::string message = message_params["message"].asString();
@@ -3263,11 +3259,6 @@ public:
} //end if invitation has instant message
else if ( input["body"].has("voice") )
{
- if (gNoRender)
- {
- return;
- }
-
if(!LLVoiceClient::getInstance()->voiceEnabled() || !LLVoiceClient::getInstance()->isVoiceWorking())
{
// Don't display voice invites unless the user has voice enabled.
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 01e0e25927..86c8a1a9b5 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4698,7 +4698,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
if (LLWearableType::getAllowMultiwear(mWearableType))
{
items.push_back(std::string("Wearable Add"));
- if (gAgentWearables.getWearableCount(mWearableType) > 0)
+ if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE)
{
disabled_items.push_back(std::string("Wearable Add"));
}
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 4cf2e723ec..b5180854ef 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1065,12 +1065,11 @@ void LLInventoryModel::idleNotifyObservers()
{
return;
}
- notifyObservers("");
+ notifyObservers();
}
// Call this method when it's time to update everyone on a new state.
-// The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328]
-void LLInventoryModel::notifyObservers(const std::string service_name)
+void LLInventoryModel::notifyObservers()
{
if (mIsNotifyObservers)
{
@@ -1087,15 +1086,7 @@ void LLInventoryModel::notifyObservers(const std::string service_name)
{
LLInventoryObserver* observer = *iter;
- if (service_name.empty())
- {
- observer->changed(mModifyMask);
- }
- else
- {
- observer->mMessageName = service_name;
- observer->changed(mModifyMask);
- }
+ observer->changed(mModifyMask);
// safe way to increment since changed may delete entries! (@!##%@!@&*!)
iter = mObservers.upper_bound(observer);
@@ -1193,7 +1184,7 @@ void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
{
changes |= gInventory.updateItem(*it);
}
- gInventory.notifyObservers("fetchinventory");
+ gInventory.notifyObservers();
gViewerWindow->getWindow()->decBusyCount();
}
@@ -1202,7 +1193,7 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str
{
llinfos << "fetchInventory::error "
<< status << ": " << reason << llendl;
- gInventory.notifyObservers("fetchinventory");
+ gInventory.notifyObservers();
}
bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index f6728fd575..15da09990f 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -425,9 +425,8 @@ public:
// has been indicated.
void idleNotifyObservers();
- // Call to explicitly update everyone on a new state. The optional argument
- // 'service_name' is used by Agent Inventory Service [DEV-20328]
- void notifyObservers(const std::string service_name="");
+ // Call to explicitly update everyone on a new state.
+ void notifyObservers();
// Allows outsiders to tell the inventory if something has
// been changed 'under the hood', but outside the control of the
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index e31360fcbc..7b1ff102e7 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -388,7 +388,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
titem->setParent(lost_uuid);
titem->updateParentOnServer(FALSE);
gInventory.updateItem(titem);
- gInventory.notifyObservers("fetchDescendents");
+ gInventory.notifyObservers();
}
}
@@ -464,7 +464,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
fetcher->setAllFoldersFetched();
}
- gInventory.notifyObservers("fetchDescendents");
+ gInventory.notifyObservers();
}
// If we get back an error (not found, etc...), handle it here.
@@ -496,7 +496,7 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str
fetcher->setAllFoldersFetched();
}
}
- gInventory.notifyObservers("fetchDescendents");
+ gInventory.notifyObservers();
}
BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const
diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp
index 0fd4b2bee5..6bf19e346d 100644
--- a/indra/newview/llinventoryobserver.cpp
+++ b/indra/newview/llinventoryobserver.cpp
@@ -572,16 +572,7 @@ void LLInventoryAddedObserver::changed(U32 mask)
// the network, figure out which item was updated.
LLMessageSystem* msg = gMessageSystem;
- std::string msg_name;
- if (mMessageName.empty())
- {
- msg_name = msg->getMessageName();
- }
- else
- {
- msg_name = mMessageName;
- }
-
+ std::string msg_name = msg->getMessageName();
if (msg_name.empty())
{
return;
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index f2a2049a51..2d9021961e 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -63,7 +63,6 @@ public:
LLInventoryObserver();
virtual ~LLInventoryObserver();
virtual void changed(U32 mask) = 0;
- std::string mMessageName; // used by Agent Inventory Service only. [DEV-20328]
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 33e051bfab..abcd8588dc 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -480,10 +480,12 @@ LLLoginInstance::LLLoginInstance() :
{
mLoginModule->getEventPump().listen("lllogininstance",
boost::bind(&LLLoginInstance::handleLoginEvent, this, _1));
- mDispatcher.add("fail.login", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1));
- mDispatcher.add("connect", boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1));
- mDispatcher.add("disconnect", boost::bind(&LLLoginInstance::handleDisconnect, this, _1));
- mDispatcher.add("indeterminate", boost::bind(&LLLoginInstance::handleIndeterminate, this, _1));
+ // This internal use of LLEventDispatcher doesn't really need
+ // per-function descriptions.
+ mDispatcher.add("fail.login", "", boost::bind(&LLLoginInstance::handleLoginFailure, this, _1));
+ mDispatcher.add("connect", "", boost::bind(&LLLoginInstance::handleLoginSuccess, this, _1));
+ mDispatcher.add("disconnect", "", boost::bind(&LLLoginInstance::handleDisconnect, this, _1));
+ mDispatcher.add("indeterminate", "", boost::bind(&LLLoginInstance::handleIndeterminate, this, _1));
}
LLLoginInstance::~LLLoginInstance()
@@ -625,11 +627,7 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event)
// Call the method registered in constructor, if any, for more specific
// handling
- LLEventDispatcher::Callable method(mDispatcher.get(event["change"]));
- if (! method.empty())
- {
- method(event);
- }
+ mDispatcher.try_call(event);
return false;
}
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 9493fddf50..5007f1c17a 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -44,6 +44,7 @@
#include "llslurl.h"
#include "lluictrlfactory.h" // LLDefaultChildRegistry
#include "llkeyboard.h"
+#include "llviewermenu.h"
// linden library includes
#include "llfocusmgr.h"
@@ -73,6 +74,7 @@ LLMediaCtrl::Params::Params()
texture_height("texture_height", 1024),
caret_color("caret_color"),
initial_mime_type("initial_mime_type"),
+ error_page_url("error_page_url"),
media_id("media_id"),
trusted_content("trusted_content", false),
focus_on_click("focus_on_click", true)
@@ -102,9 +104,11 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
mTextureHeight ( 1024 ),
mClearCache(false),
mHomePageMimeType(p.initial_mime_type),
+ mErrorPageURL(p.error_page_url),
mTrusted(p.trusted_content),
mWindowShade(NULL),
- mHoverTextChanged(false)
+ mHoverTextChanged(false),
+ mContextMenu(NULL)
{
{
LLColor4 color = p.caret_color().get();
@@ -149,7 +153,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
LLMediaCtrl::~LLMediaCtrl()
{
-
if (mMediaSource)
{
mMediaSource->remObserver( this );
@@ -304,10 +307,12 @@ BOOL LLMediaCtrl::handleRightMouseUp( S32 x, S32 y, MASK mask )
BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
{
if (LLPanel::handleRightMouseDown(x, y, mask)) return TRUE;
- convertInputCoords(x, y);
+
+ S32 media_x = x, media_y = y;
+ convertInputCoords(media_x, media_y);
if (mMediaSource)
- mMediaSource->mouseDown(x, y, mask, 1);
+ mMediaSource->mouseDown(media_x, media_y, mask, 1);
gFocusMgr.setMouseCapture( this );
@@ -316,6 +321,12 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
setFocus( TRUE );
}
+ if (mContextMenu)
+ {
+ mContextMenu->show(x, y);
+ LLMenuGL::showPopup(this, mContextMenu, x, y);
+ }
+
return TRUE;
}
@@ -378,6 +389,8 @@ void LLMediaCtrl::onFocusLost()
//
BOOL LLMediaCtrl::postBuild ()
{
+ mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
+ "menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
return TRUE;
}
@@ -503,22 +516,6 @@ bool LLMediaCtrl::canNavigateForward()
////////////////////////////////////////////////////////////////////////////////
//
-void LLMediaCtrl::set404RedirectUrl( std::string redirect_url )
-{
- if(mMediaSource && mMediaSource->hasMedia())
- mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url );
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLMediaCtrl::clr404RedirectUrl()
-{
- if(mMediaSource && mMediaSource->hasMedia())
- mMediaSource->getMediaPlugin()->set_status_redirect(404, "");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
void LLMediaCtrl::clearCache()
{
if(mMediaSource)
@@ -626,6 +623,16 @@ void LLMediaCtrl::setTarget(const std::string& target)
}
}
+void LLMediaCtrl::setErrorPageURL(const std::string& url)
+{
+ mErrorPageURL = url;
+}
+
+const std::string& LLMediaCtrl::getErrorPageURL()
+{
+ return mErrorPageURL;
+}
+
////////////////////////////////////////////////////////////////////////////////
//
bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue)
@@ -976,6 +983,16 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
};
break;
+ case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;
+ if ( mErrorPageURL.length() > 0 )
+ {
+ navigateTo(mErrorPageURL, "text/html");
+ };
+ };
+ break;
+
case MEDIA_EVENT_CLICK_LINK_HREF:
{
LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 38a74f90d3..28666e620f 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -34,6 +34,7 @@
class LLViewBorder;
class LLUICtrlFactory;
+class LLContextMenu;
////////////////////////////////////////////////////////////////////////////////
//
@@ -63,6 +64,7 @@ public:
Optional<std::string> initial_mime_type;
Optional<std::string> media_id;
+ Optional<std::string> error_page_url;
Params();
};
@@ -113,10 +115,9 @@ public:
void setTarget(const std::string& target);
- // set/clear URL to visit when a 404 page is reached
- void set404RedirectUrl( std::string redirect_url );
- void clr404RedirectUrl();
-
+ void setErrorPageURL(const std::string& url);
+ const std::string& getErrorPageURL();
+
// Clear the browser cache when the instance gets loaded
void clearCache();
@@ -179,6 +180,7 @@ public:
std::string mHomePageUrl;
std::string mHomePageMimeType;
std::string mCurrentNavUrl;
+ std::string mErrorPageURL;
std::string mTarget;
bool mIgnoreUIScale;
bool mAlwaysRefresh;
@@ -194,6 +196,7 @@ public:
bool mClearCache;
class LLWindowShade* mWindowShade;
bool mHoverTextChanged;
+ LLContextMenu* mContextMenu;
};
#endif // LL_LLMediaCtrl_H
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 3b160ddc8e..b8832dfd8e 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -57,6 +57,7 @@
#include "llviewercontrol.h"
#include "llfloatermediabrowser.h"
#include "llweb.h"
+#include "llhints.h"
#include "llinventorymodel.h"
#include "lllandmarkactions.h"
@@ -324,6 +325,8 @@ BOOL LLNavigationBar::postBuild()
LLTeleportHistory::getInstance()->setHistoryChangedCallback(
boost::bind(&LLNavigationBar::onTeleportHistoryChanged, this));
+ LLHints::registerHintTarget("nav_bar", LLView::getHandle());
+
return TRUE;
}
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 8bd2d5ad6a..cb8fbd66b5 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -1196,6 +1196,12 @@ void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index)
void LLPanelEditWearable::changeCamera(U8 subpart)
{
+ // Don't change the camera if this type doesn't have a camera switch.
+ // Useful for wearables like physics that don't have an associated physical body part.
+ if (LLWearableType::getDisableCameraSwitch(mWearablePtr->getType()))
+ {
+ return;
+ }
const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mWearablePtr->getType());
if (!wearable_entry)
{
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 903cf4780d..7820ac3ecd 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -214,7 +214,9 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
}
updateLocationCombo(false);
- gSavedSettings.getControl("SessionSettingsFile")->getSignal()->connect(boost::bind(&onModeChange));
+ LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo");
+ mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile"));
+ mode_combo.setCommitCallback(boost::bind(&LLPanelLogin::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2));
LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
server_choice_combo->setCommitCallback(onSelectServer, NULL);
@@ -1159,23 +1161,26 @@ void LLPanelLogin::updateLoginPanelLinks()
sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
}
-//static
-void LLPanelLogin::onModeChange()
+void LLPanelLogin::onModeChange(const LLSD& original_value, const LLSD& new_value)
{
- LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&onModeChangeConfirm, _1, _2));
+ if (original_value.asString() != new_value.asString())
+ {
+ LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLPanelLogin::onModeChangeConfirm, this, original_value, new_value, _1, _2));
+ }
}
-//static
-void LLPanelLogin::onModeChangeConfirm(const LLSD& notification, const LLSD& response)
+void LLPanelLogin::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
switch (option)
{
case 0:
- LLAppViewer::instance()->requestQuit();
+ gSavedSettings.getControl("SessionSettingsFile")->set(new_value);
+ LLAppViewer::instance()->forceQuit();
break;
case 1:
- // do nothing
+ // revert to original value
+ getChild<LLUICtrl>("mode_combo")->setValue(original_value);
break;
default:
break;
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 1430bec832..9cc5e3456a 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -98,8 +98,8 @@ private:
static void onServerComboLostFocus(LLFocusableElement*);
static void updateServerCombo();
static void updateStartSLURL();
- static void onModeChange();
- static void onModeChangeConfirm(const LLSD& notification, const LLSD& response);
+ void onModeChange(const LLSD& original_value, const LLSD& new_value);
+ void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
static void updateLoginPanelLinks();
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index d3c9c3e131..1347a02a52 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -67,8 +67,6 @@ BOOL LLPanelMe::postBuild()
{
LLPanelProfile::postBuild();
- getTabContainer()[PANEL_PROFILE]->childSetAction("edit_profile_btn", boost::bind(&LLPanelMe::onEditProfileClicked, this), this);
-
return TRUE;
}
@@ -135,7 +133,11 @@ void LLPanelMe::buildEditPanel()
if (NULL == mEditPanel)
{
mEditPanel = new LLPanelMyProfileEdit();
- mEditPanel->childSetAction("save_btn", boost::bind(&LLPanelMe::onSaveChangesClicked, this), this);
+
+ // Note: Remove support for editing profile through this method.
+ // All profile editing should go through the web.
+ //mEditPanel->childSetAction("save_btn", boost::bind(&LLPanelMe::onSaveChangesClicked, this), this);
+
mEditPanel->childSetAction("cancel_btn", boost::bind(&LLPanelMe::onCancelClicked, this), this);
}
}
@@ -147,22 +149,6 @@ void LLPanelMe::onEditProfileClicked()
togglePanel(mEditPanel, getAvatarId()); // open
}
-void LLPanelMe::onSaveChangesClicked()
-{
- LLAvatarData data = LLAvatarData();
- data.avatar_id = gAgent.getID();
- data.image_id = mEditPanel->getChild<LLTextureCtrl>(PICKER_SECOND_LIFE)->getImageAssetID();
- data.fl_image_id = mEditPanel->getChild<LLTextureCtrl>(PICKER_FIRST_LIFE)->getImageAssetID();
- data.about_text = mEditPanel->getChild<LLUICtrl>("sl_description_edit")->getValue().asString();
- data.fl_about_text = mEditPanel->getChild<LLUICtrl>("fl_description_edit")->getValue().asString();
- data.profile_url = mEditPanel->getChild<LLUICtrl>("homepage_edit")->getValue().asString();
- data.allow_publish = mEditPanel->getChild<LLUICtrl>("show_in_search_checkbox")->getValue();
-
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(&data);
- togglePanel(mEditPanel); // close
- onOpen(getAvatarId());
-}
-
void LLPanelMe::onCancelClicked()
{
togglePanel(mEditPanel); // close
diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h
index d5b2fee869..f27f5a268e 100644
--- a/indra/newview/llpanelme.h
+++ b/indra/newview/llpanelme.h
@@ -58,7 +58,6 @@ private:
void buildEditPanel();
void onEditProfileClicked();
- void onSaveChangesClicked();
void onCancelClicked();
LLPanelMyProfileEdit * mEditPanel;
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index c15e72744f..f40056adbc 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -1,701 +1,717 @@
-/**
- * @file llphysicsmotion.cpp
- * @brief Implementation of LLPhysicsMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "llviewerprecompiledheaders.h"
-#include "linden_common.h"
-
-#include "m3math.h"
-#include "v3dmath.h"
-
-#include "llphysicsmotion.h"
-#include "llcharacter.h"
-#include "llviewercontrol.h"
-#include "llviewervisualparam.h"
-#include "llvoavatarself.h"
-
-typedef std::map<std::string, std::string> controller_map_t;
-typedef std::map<std::string, F32> default_controller_map_t;
-
-#define MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION 0.f;
-
-inline F64 llsgn(const F64 a)
-{
- if (a >= 0)
- return 1;
- return -1;
-}
-
-/*
- At a high level, this works by setting temporary parameters that are not stored
- in the avatar's list of params, and are not conveyed to other users. We accomplish
- this by creating some new temporary driven params inside avatar_lad that are then driven
- by the actual params that the user sees and sets. For example, in the old system,
- the user sets a param called breast bouyancy, which controls the Z value of the breasts.
- In our new system, the user still sets the breast bouyancy, but that param is redefined
- as a driver param so that affects a new temporary driven param that the bounce is applied
- to.
-*/
-
-class LLPhysicsMotion
-{
-public:
- /*
- param_driver_name: The param that controls the params that are being affected by the physics.
- joint_name: The joint that the body part is attached to. The joint is
- used to determine the orientation (rotation) of the body part.
-
- character: The avatar that this physics affects.
-
- motion_direction_vec: The direction (in world coordinates) that determines the
- motion. For example, (0,0,1) is up-down, and means that up-down motion is what
- determines how this joint moves.
-
- controllers: The various settings (e.g. spring force, mass) that determine how
- the body part behaves.
- */
- LLPhysicsMotion(const std::string &param_driver_name,
- const std::string &joint_name,
- LLCharacter *character,
- const LLVector3 &motion_direction_vec,
- const controller_map_t &controllers) :
- mParamDriverName(param_driver_name),
- mJointName(joint_name),
- mMotionDirectionVec(motion_direction_vec),
- mParamDriver(NULL),
- mParamControllers(controllers),
- mCharacter(character),
- mLastTime(0),
- mPosition_local(0),
- mVelocityJoint_local(0),
- mPositionLastUpdate_local(0)
- {
- mJointState = new LLJointState;
- }
-
- BOOL initialize();
-
- ~LLPhysicsMotion() {}
-
- BOOL onUpdate(F32 time);
-
- LLPointer<LLJointState> getJointState()
- {
- return mJointState;
- }
-protected:
- F32 getParamValue(const std::string& controller_key)
- {
- const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key);
- if (entry == mParamControllers.end())
- {
- return sDefaultController[controller_key];
- }
- const std::string& param_name = (*entry).second.c_str();
- return mCharacter->getVisualParamWeight(param_name.c_str());
- }
- void setParamValue(LLViewerVisualParam *param,
- const F32 new_value_local);
-
- F32 toLocal(const LLVector3 &world);
- F32 calculateVelocity_local(const F32 time_delta);
- F32 calculateAcceleration_local(F32 velocity_local,
- const F32 time_delta);
-private:
- const std::string mParamDriverName;
- const std::string mParamControllerName;
- const LLVector3 mMotionDirectionVec;
- const std::string mJointName;
-
- F32 mPosition_local;
- F32 mVelocityJoint_local; // How fast the joint is moving
- F32 mAccelerationJoint_local; // Acceleration on the joint
-
- F32 mVelocity_local; // How fast the param is moving
- F32 mPositionLastUpdate_local;
- LLVector3 mPosition_world;
-
- LLViewerVisualParam *mParamDriver;
- const controller_map_t mParamControllers;
-
- LLPointer<LLJointState> mJointState;
- LLCharacter *mCharacter;
-
- F32 mLastTime;
-
- static default_controller_map_t sDefaultController;
-};
-
-default_controller_map_t initDefaultController()
-{
- default_controller_map_t controller;
- controller["Mass"] = 0.2f;
- controller["Gravity"] = 0.0f;
- controller["Damping"] = .05f;
- controller["Drag"] = 0.15f;
- controller["MaxEffect"] = 0.1f;
- controller["Spring"] = 0.1f;
- controller["Gain"] = 10.0f;
- return controller;
-}
-
-default_controller_map_t LLPhysicsMotion::sDefaultController = initDefaultController();
-
-BOOL LLPhysicsMotion::initialize()
-{
- if (!mJointState->setJoint(mCharacter->getJoint(mJointName.c_str())))
- return FALSE;
- mJointState->setUsage(LLJointState::ROT);
-
- mParamDriver = (LLViewerVisualParam*)mCharacter->getVisualParam(mParamDriverName.c_str());
- if (mParamDriver == NULL)
- {
- llinfos << "Failure reading in [ " << mParamDriverName << " ]" << llendl;
- return FALSE;
- }
-
- return TRUE;
-}
-
-LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) :
- LLMotion(id),
- mCharacter(NULL)
-{
- mName = "breast_motion";
-}
-
-LLPhysicsMotionController::~LLPhysicsMotionController()
-{
- for (motion_vec_t::iterator iter = mMotions.begin();
- iter != mMotions.end();
- ++iter)
- {
- delete (*iter);
- }
-}
-
-BOOL LLPhysicsMotionController::onActivate()
-{
- return TRUE;
-}
-
-void LLPhysicsMotionController::onDeactivate()
-{
-}
-
-LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character)
-{
- mCharacter = character;
-
- mMotions.clear();
-
- // Breast Cleavage
- {
- controller_map_t controller;
- controller["Mass"] = "Breast_Physics_Mass";
- controller["Gravity"] = "Breast_Physics_Gravity";
- controller["Drag"] = "Breast_Physics_Drag";
- controller["Damping"] = "Breast_Physics_InOut_Damping";
- controller["MaxEffect"] = "Breast_Physics_InOut_Max_Effect";
- controller["Spring"] = "Breast_Physics_InOut_Spring";
- controller["Gain"] = "Breast_Physics_InOut_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_InOut_Controller",
- "mChest",
- character,
- LLVector3(-1,0,0),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
-
- // Breast Bounce
- {
- controller_map_t controller;
- controller["Mass"] = "Breast_Physics_Mass";
- controller["Gravity"] = "Breast_Physics_Gravity";
- controller["Drag"] = "Breast_Physics_Drag";
- controller["Damping"] = "Breast_Physics_UpDown_Damping";
- controller["MaxEffect"] = "Breast_Physics_UpDown_Max_Effect";
- controller["Spring"] = "Breast_Physics_UpDown_Spring";
- controller["Gain"] = "Breast_Physics_UpDown_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_UpDown_Controller",
- "mChest",
- character,
- LLVector3(0,0,1),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
-
- // Breast Sway
- {
- controller_map_t controller;
- controller["Mass"] = "Breast_Physics_Mass";
- controller["Gravity"] = "Breast_Physics_Gravity";
- controller["Drag"] = "Breast_Physics_Drag";
- controller["Damping"] = "Breast_Physics_LeftRight_Damping";
- controller["MaxEffect"] = "Breast_Physics_LeftRight_Max_Effect";
- controller["Spring"] = "Breast_Physics_LeftRight_Spring";
- controller["Gain"] = "Breast_Physics_LeftRight_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_LeftRight_Controller",
- "mChest",
- character,
- LLVector3(0,-1,0),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
- // Butt Bounce
- {
- controller_map_t controller;
- controller["Mass"] = "Butt_Physics_Mass";
- controller["Gravity"] = "Butt_Physics_Gravity";
- controller["Drag"] = "Butt_Physics_Drag";
- controller["Damping"] = "Butt_Physics_UpDown_Damping";
- controller["MaxEffect"] = "Butt_Physics_UpDown_Max_Effect";
- controller["Spring"] = "Butt_Physics_UpDown_Spring";
- controller["Gain"] = "Butt_Physics_UpDown_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_UpDown_Controller",
- "mPelvis",
- character,
- LLVector3(0,0,-1),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
-
- // Butt LeftRight
- {
- controller_map_t controller;
- controller["Mass"] = "Butt_Physics_Mass";
- controller["Gravity"] = "Butt_Physics_Gravity";
- controller["Drag"] = "Butt_Physics_Drag";
- controller["Damping"] = "Butt_Physics_LeftRight_Damping";
- controller["MaxEffect"] = "Butt_Physics_LeftRight_Max_Effect";
- controller["Spring"] = "Butt_Physics_LeftRight_Spring";
- controller["Gain"] = "Butt_Physics_LeftRight_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_LeftRight_Controller",
- "mPelvis",
- character,
- LLVector3(0,-1,0),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
-
- // Belly Bounce
- {
- controller_map_t controller;
- controller["Mass"] = "Belly_Physics_Mass";
- controller["Gravity"] = "Belly_Physics_Gravity";
- controller["Drag"] = "Belly_Physics_Drag";
- controller["Damping"] = "Belly_Physics_UpDown_Damping";
- controller["MaxEffect"] = "Belly_Physics_UpDown_Max_Effect";
- controller["Spring"] = "Belly_Physics_UpDown_Spring";
- controller["Gain"] = "Belly_Physics_UpDown_Gain";
- LLPhysicsMotion *motion = new LLPhysicsMotion("Belly_Physics_UpDown_Controller",
- "mPelvis",
- character,
- LLVector3(0,0,-1),
- controller);
- if (!motion->initialize())
- {
- llassert_always(FALSE);
- return STATUS_FAILURE;
- }
- addMotion(motion);
- }
-
- return STATUS_SUCCESS;
-}
-
-void LLPhysicsMotionController::addMotion(LLPhysicsMotion *motion)
-{
- addJointState(motion->getJointState());
- mMotions.push_back(motion);
-}
-
-F32 LLPhysicsMotionController::getMinPixelArea()
-{
- return MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION;
-}
-
-// Local space means "parameter space".
-F32 LLPhysicsMotion::toLocal(const LLVector3 &world)
-{
- LLJoint *joint = mJointState->getJoint();
- const LLQuaternion rotation_world = joint->getWorldRotation();
-
- LLVector3 dir_world = mMotionDirectionVec * rotation_world;
- dir_world.normalize();
- return world * dir_world;
-}
-
-F32 LLPhysicsMotion::calculateVelocity_local(const F32 time_delta)
-{
- LLJoint *joint = mJointState->getJoint();
- const LLVector3 position_world = joint->getWorldPosition();
- const LLQuaternion rotation_world = joint->getWorldRotation();
- const LLVector3 last_position_world = mPosition_world;
- const LLVector3 velocity_world = (position_world-last_position_world) / time_delta;
- const F32 velocity_local = toLocal(velocity_world);
- return velocity_local;
-}
-
-F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local,
- const F32 time_delta)
-{
-// const F32 smoothing = getParamValue("Smoothing");
- static const F32 smoothing = 3.0f; // Removed smoothing param since it's probably not necessary
- const F32 acceleration_local = velocity_local - mVelocityJoint_local;
-
- const F32 smoothed_acceleration_local =
- acceleration_local * 1.0/smoothing +
- mAccelerationJoint_local * (smoothing-1.0)/smoothing;
-
- return smoothed_acceleration_local;
-}
-
-BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
-{
- // Skip if disabled globally.
- if (!gSavedSettings.getBOOL("AvatarPhysics"))
- {
- return TRUE;
- }
-
- BOOL update_visuals = FALSE;
- for (motion_vec_t::iterator iter = mMotions.begin();
- iter != mMotions.end();
- ++iter)
- {
- LLPhysicsMotion *motion = (*iter);
- update_visuals |= motion->onUpdate(time);
- }
-
- if (update_visuals)
- mCharacter->updateVisualParams();
-
- return TRUE;
-}
-
-
-// Return TRUE if character has to update visual params.
-BOOL LLPhysicsMotion::onUpdate(F32 time)
-{
- // static FILE *mFileWrite = fopen("c:\\temp\\avatar_data.txt","w");
-
- if (!mParamDriver)
- return FALSE;
-
- if (!mLastTime)
- {
- mLastTime = time;
- return FALSE;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // Get all parameters and settings
- //
-
- const F32 time_delta = time - mLastTime;
- if (time_delta > 3.0 || time_delta <= 0.01)
- {
- mLastTime = time;
- return FALSE;
- }
-
- // Higher LOD is better. This controls the granularity
- // and frequency of updates for the motions.
- const F32 lod_factor = LLVOAvatar::sPhysicsLODFactor;
- if (lod_factor == 0)
- {
- return TRUE;
- }
-
- LLJoint *joint = mJointState->getJoint();
-
- const F32 behavior_mass = getParamValue("Mass");
- const F32 behavior_gravity = getParamValue("Gravity");
- const F32 behavior_spring = getParamValue("Spring");
- const F32 behavior_gain = getParamValue("Gain");
- const F32 behavior_damping = getParamValue("Damping");
- const F32 behavior_drag = getParamValue("Drag");
- const BOOL physics_test = gSavedSettings.getBOOL("AvatarPhysicsTest");
-
- F32 behavior_maxeffect = getParamValue("MaxEffect");
- if (physics_test)
- behavior_maxeffect = 1.0f;
- // Maximum effect is [0,1] range.
- const F32 min_val = 0.5f-behavior_maxeffect/2.0;
- const F32 max_val = 0.5f+behavior_maxeffect/2.0;
-
- // mPositon_local should be in normalized 0,1 range already. Just making sure...
- F32 position_current_local = llclamp(mPosition_local,
- 0.0f,
- 1.0f);
-
- // Normalize the param position to be from [0,1].
- // We have to use normalized values because there may be more than one driven param,
- // and each of these driven params may have its own range.
- // This means we'll do all our calculations in normalized [0,1] local coordinates.
- F32 position_user_local = mParamDriver->getWeight();
- position_user_local = (position_user_local - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight());
-
- // If the effect is turned off then don't process unless we need one more update
- // to set the position to the default (i.e. user) position.
- if ((behavior_maxeffect == 0) && (position_current_local == position_user_local))
- {
- return FALSE;
- }
-
- //
- // End parameters and settings
- ////////////////////////////////////////////////////////////////////////////////
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // Calculate velocity and acceleration in parameter space.
- //
-
- const F32 velocity_joint_local = calculateVelocity_local(time_delta);
- const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_delta);
-
- //
- // End velocity and acceleration
- ////////////////////////////////////////////////////////////////////////////////
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // Calculate the total force
- //
-
- // Spring force is a restoring force towards the original user-set breast position.
- // F = kx
- const F32 spring_length = position_current_local - position_user_local;
- const F32 force_spring = -spring_length * behavior_spring;
-
- // Acceleration is the force that comes from the change in velocity of the torso.
- // F = ma
- const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass);
-
- // Gravity always points downward in world space.
- // F = mg
- const LLVector3 gravity_world(0,0,1);
- const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass);
-
- // Damping is a restoring force that opposes the current velocity.
- // F = -kv
- const F32 force_damping = -behavior_damping * mVelocity_local;
-
- // Drag is a force imparted by velocity (intuitively it is similar to wind resistance)
- // F = .5kv^2
- const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local);
-
- const F32 force_net = (force_accel +
- force_gravity +
- force_spring +
- force_damping +
- force_drag);
-
- //
- // End total force
- ////////////////////////////////////////////////////////////////////////////////
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // Calculate new params
- //
-
- // Calculate the new acceleration based on the net force.
- // a = F/m
- const F32 acceleration_new_local = force_net / behavior_mass;
- static const F32 max_acceleration = 10.0f; // magic number, used to be customizable.
- F32 velocity_new_local = mVelocity_local + acceleration_new_local;
- velocity_new_local = llclamp(velocity_new_local,
- -max_acceleration, max_acceleration);
-
- // Temporary debugging setting to cause all avatars to move, for profiling purposes.
- if (physics_test)
- {
- velocity_new_local = sin(time*4.0);
- }
- // Calculate the new parameters, or remain unchanged if max speed is 0.
- F32 position_new_local = position_current_local + velocity_new_local*time_delta;
- if (behavior_maxeffect == 0)
- position_new_local = position_user_local;
-
- // Zero out the velocity if the param is being pushed beyond its limits.
- if ((position_new_local < min_val && velocity_new_local < 0) ||
- (position_new_local > max_val && velocity_new_local > 0))
- {
- velocity_new_local = 0;
- }
-
- const F32 position_new_local_clamped = llclamp(position_new_local,
- min_val,
- max_val);
-
- LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver);
- llassert_always(driver_param);
- if (driver_param)
- {
- // If this is one of our "hidden" driver params, then make sure it's
- // the default value.
- if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
- (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
- {
- mCharacter->setVisualParamWeight(driver_param,
- 0,
- FALSE);
- }
- for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin();
- iter != driver_param->mDriven.end();
- ++iter)
- {
- LLDrivenEntry &entry = (*iter);
- LLViewerVisualParam *driven_param = entry.mParam;
- setParamValue(driven_param,position_new_local_clamped);
- }
- }
-
- //
- // End calculate new params
- ////////////////////////////////////////////////////////////////////////////////
-
- ////////////////////////////////////////////////////////////////////////////////
- // Conditionally update the visual params
- //
-
- // Updating the visual params (i.e. what the user sees) is fairly expensive.
- // So only update if the params have changed enough, and also take into account
- // the graphics LOD settings.
-
- BOOL update_visuals = FALSE;
-
- // For non-self, if the avatar is small enough visually, then don't update.
- const F32 area_for_max_settings = 0.0;
- const F32 area_for_min_settings = 1400.0;
- const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor);
- const F32 pixel_area = sqrtf(mCharacter->getPixelArea());
-
- const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(mCharacter) != NULL);
- if ((pixel_area > area_for_this_setting) || is_self)
- {
- const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped);
- const F32 min_delta = (1.01f-lod_factor)*0.4f;
- if (llabs(position_diff_local) > min_delta)
- {
- update_visuals = TRUE;
- mPositionLastUpdate_local = position_new_local;
- }
- }
-
- //
- // End update visual params
- ////////////////////////////////////////////////////////////////////////////////
-
- mVelocityJoint_local = velocity_joint_local;
-
- mVelocity_local = velocity_new_local;
- mAccelerationJoint_local = acceleration_joint_local;
- mPosition_local = position_new_local;
-
- mPosition_world = joint->getWorldPosition();
- mLastTime = time;
-
- /*
- // Write out debugging info into a spreadsheet.
- if (mFileWrite != NULL && is_self)
- {
- fprintf(mFileWrite,"%f\t%f\t%f \t\t%f \t\t%f\t%f\t%f\t \t\t%f\t%f\t%f\t%f\t%f \t\t%f\t%f\t%f\n",
- position_new_local,
- velocity_new_local,
- acceleration_new_local,
-
- time_delta,
-
- mPosition_world[0],
- mPosition_world[1],
- mPosition_world[2],
-
- force_net,
- force_spring,
- force_accel,
- force_damping,
- force_drag,
-
- spring_length,
- velocity_joint_local,
- acceleration_joint_local
- );
- }
- */
-
- return update_visuals;
-}
-
-// Range of new_value_local is assumed to be [0 , 1] normalized.
-void LLPhysicsMotion::setParamValue(LLViewerVisualParam *param,
- F32 new_value_normalized)
-{
- const F32 value_min_local = param->getMinWeight();
- const F32 value_max_local = param->getMaxWeight();
-
- const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_normalized;
-
- mCharacter->setVisualParamWeight(param,
- new_value_local,
- FALSE);
-}
+/**
+ * @file llphysicsmotion.cpp
+ * @brief Implementation of LLPhysicsMotion class.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+
+#include "m3math.h"
+#include "v3dmath.h"
+
+#include "llphysicsmotion.h"
+#include "llagent.h"
+#include "llcharacter.h"
+#include "llviewercontrol.h"
+#include "llviewervisualparam.h"
+#include "llvoavatarself.h"
+
+typedef std::map<std::string, std::string> controller_map_t;
+typedef std::map<std::string, F32> default_controller_map_t;
+
+#define MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION 0.f;
+
+inline F64 llsgn(const F64 a)
+{
+ if (a >= 0)
+ return 1;
+ return -1;
+}
+
+/*
+ At a high level, this works by setting temporary parameters that are not stored
+ in the avatar's list of params, and are not conveyed to other users. We accomplish
+ this by creating some new temporary driven params inside avatar_lad that are then driven
+ by the actual params that the user sees and sets. For example, in the old system,
+ the user sets a param called breast bouyancy, which controls the Z value of the breasts.
+ In our new system, the user still sets the breast bouyancy, but that param is redefined
+ as a driver param so that affects a new temporary driven param that the bounce is applied
+ to.
+*/
+
+class LLPhysicsMotion
+{
+public:
+ /*
+ param_driver_name: The param that controls the params that are being affected by the physics.
+ joint_name: The joint that the body part is attached to. The joint is
+ used to determine the orientation (rotation) of the body part.
+
+ character: The avatar that this physics affects.
+
+ motion_direction_vec: The direction (in world coordinates) that determines the
+ motion. For example, (0,0,1) is up-down, and means that up-down motion is what
+ determines how this joint moves.
+
+ controllers: The various settings (e.g. spring force, mass) that determine how
+ the body part behaves.
+ */
+ LLPhysicsMotion(const std::string &param_driver_name,
+ const std::string &joint_name,
+ LLCharacter *character,
+ const LLVector3 &motion_direction_vec,
+ const controller_map_t &controllers) :
+ mParamDriverName(param_driver_name),
+ mJointName(joint_name),
+ mMotionDirectionVec(motion_direction_vec),
+ mParamDriver(NULL),
+ mParamControllers(controllers),
+ mCharacter(character),
+ mLastTime(0),
+ mPosition_local(0),
+ mVelocityJoint_local(0),
+ mPositionLastUpdate_local(0)
+ {
+ mJointState = new LLJointState;
+ }
+
+ BOOL initialize();
+
+ ~LLPhysicsMotion() {}
+
+ BOOL onUpdate(F32 time);
+
+ LLPointer<LLJointState> getJointState()
+ {
+ return mJointState;
+ }
+protected:
+ F32 getParamValue(const std::string& controller_key)
+ {
+ const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key);
+ if (entry == mParamControllers.end())
+ {
+ return sDefaultController[controller_key];
+ }
+ const std::string& param_name = (*entry).second.c_str();
+ return mCharacter->getVisualParamWeight(param_name.c_str());
+ }
+ void setParamValue(LLViewerVisualParam *param,
+ const F32 new_value_local,
+ F32 behavior_maxeffect);
+
+ F32 toLocal(const LLVector3 &world);
+ F32 calculateVelocity_local(const F32 time_delta);
+ F32 calculateAcceleration_local(F32 velocity_local,
+ const F32 time_delta);
+private:
+ const std::string mParamDriverName;
+ const std::string mParamControllerName;
+ const LLVector3 mMotionDirectionVec;
+ const std::string mJointName;
+
+ F32 mPosition_local;
+ F32 mVelocityJoint_local; // How fast the joint is moving
+ F32 mAccelerationJoint_local; // Acceleration on the joint
+
+ F32 mVelocity_local; // How fast the param is moving
+ F32 mPositionLastUpdate_local;
+ LLVector3 mPosition_world;
+
+ LLViewerVisualParam *mParamDriver;
+ const controller_map_t mParamControllers;
+
+ LLPointer<LLJointState> mJointState;
+ LLCharacter *mCharacter;
+
+ F32 mLastTime;
+
+ static default_controller_map_t sDefaultController;
+};
+
+default_controller_map_t initDefaultController()
+{
+ default_controller_map_t controller;
+ controller["Mass"] = 0.2f;
+ controller["Gravity"] = 0.0f;
+ controller["Damping"] = .05f;
+ controller["Drag"] = 0.15f;
+ controller["MaxEffect"] = 0.1f;
+ controller["Spring"] = 0.1f;
+ controller["Gain"] = 10.0f;
+ return controller;
+}
+
+default_controller_map_t LLPhysicsMotion::sDefaultController = initDefaultController();
+
+BOOL LLPhysicsMotion::initialize()
+{
+ if (!mJointState->setJoint(mCharacter->getJoint(mJointName.c_str())))
+ return FALSE;
+ mJointState->setUsage(LLJointState::ROT);
+
+ mParamDriver = (LLViewerVisualParam*)mCharacter->getVisualParam(mParamDriverName.c_str());
+ if (mParamDriver == NULL)
+ {
+ llinfos << "Failure reading in [ " << mParamDriverName << " ]" << llendl;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) :
+ LLMotion(id),
+ mCharacter(NULL)
+{
+ mName = "breast_motion";
+}
+
+LLPhysicsMotionController::~LLPhysicsMotionController()
+{
+ for (motion_vec_t::iterator iter = mMotions.begin();
+ iter != mMotions.end();
+ ++iter)
+ {
+ delete (*iter);
+ }
+}
+
+BOOL LLPhysicsMotionController::onActivate()
+{
+ return TRUE;
+}
+
+void LLPhysicsMotionController::onDeactivate()
+{
+}
+
+LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character)
+{
+ mCharacter = character;
+
+ mMotions.clear();
+
+ // Breast Cleavage
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Breast_Physics_Mass";
+ controller["Gravity"] = "Breast_Physics_Gravity";
+ controller["Drag"] = "Breast_Physics_Drag";
+ controller["Damping"] = "Breast_Physics_InOut_Damping";
+ controller["MaxEffect"] = "Breast_Physics_InOut_Max_Effect";
+ controller["Spring"] = "Breast_Physics_InOut_Spring";
+ controller["Gain"] = "Breast_Physics_InOut_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_InOut_Controller",
+ "mChest",
+ character,
+ LLVector3(-1,0,0),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+
+ // Breast Bounce
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Breast_Physics_Mass";
+ controller["Gravity"] = "Breast_Physics_Gravity";
+ controller["Drag"] = "Breast_Physics_Drag";
+ controller["Damping"] = "Breast_Physics_UpDown_Damping";
+ controller["MaxEffect"] = "Breast_Physics_UpDown_Max_Effect";
+ controller["Spring"] = "Breast_Physics_UpDown_Spring";
+ controller["Gain"] = "Breast_Physics_UpDown_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_UpDown_Controller",
+ "mChest",
+ character,
+ LLVector3(0,0,1),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+
+ // Breast Sway
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Breast_Physics_Mass";
+ controller["Gravity"] = "Breast_Physics_Gravity";
+ controller["Drag"] = "Breast_Physics_Drag";
+ controller["Damping"] = "Breast_Physics_LeftRight_Damping";
+ controller["MaxEffect"] = "Breast_Physics_LeftRight_Max_Effect";
+ controller["Spring"] = "Breast_Physics_LeftRight_Spring";
+ controller["Gain"] = "Breast_Physics_LeftRight_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_LeftRight_Controller",
+ "mChest",
+ character,
+ LLVector3(0,-1,0),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+ // Butt Bounce
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Butt_Physics_Mass";
+ controller["Gravity"] = "Butt_Physics_Gravity";
+ controller["Drag"] = "Butt_Physics_Drag";
+ controller["Damping"] = "Butt_Physics_UpDown_Damping";
+ controller["MaxEffect"] = "Butt_Physics_UpDown_Max_Effect";
+ controller["Spring"] = "Butt_Physics_UpDown_Spring";
+ controller["Gain"] = "Butt_Physics_UpDown_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_UpDown_Controller",
+ "mPelvis",
+ character,
+ LLVector3(0,0,-1),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+
+ // Butt LeftRight
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Butt_Physics_Mass";
+ controller["Gravity"] = "Butt_Physics_Gravity";
+ controller["Drag"] = "Butt_Physics_Drag";
+ controller["Damping"] = "Butt_Physics_LeftRight_Damping";
+ controller["MaxEffect"] = "Butt_Physics_LeftRight_Max_Effect";
+ controller["Spring"] = "Butt_Physics_LeftRight_Spring";
+ controller["Gain"] = "Butt_Physics_LeftRight_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_LeftRight_Controller",
+ "mPelvis",
+ character,
+ LLVector3(0,-1,0),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+
+ // Belly Bounce
+ {
+ controller_map_t controller;
+ controller["Mass"] = "Belly_Physics_Mass";
+ controller["Gravity"] = "Belly_Physics_Gravity";
+ controller["Drag"] = "Belly_Physics_Drag";
+ controller["Damping"] = "Belly_Physics_UpDown_Damping";
+ controller["MaxEffect"] = "Belly_Physics_UpDown_Max_Effect";
+ controller["Spring"] = "Belly_Physics_UpDown_Spring";
+ controller["Gain"] = "Belly_Physics_UpDown_Gain";
+ LLPhysicsMotion *motion = new LLPhysicsMotion("Belly_Physics_UpDown_Controller",
+ "mPelvis",
+ character,
+ LLVector3(0,0,-1),
+ controller);
+ if (!motion->initialize())
+ {
+ llassert_always(FALSE);
+ return STATUS_FAILURE;
+ }
+ addMotion(motion);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void LLPhysicsMotionController::addMotion(LLPhysicsMotion *motion)
+{
+ addJointState(motion->getJointState());
+ mMotions.push_back(motion);
+}
+
+F32 LLPhysicsMotionController::getMinPixelArea()
+{
+ return MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION;
+}
+
+// Local space means "parameter space".
+F32 LLPhysicsMotion::toLocal(const LLVector3 &world)
+{
+ LLJoint *joint = mJointState->getJoint();
+ const LLQuaternion rotation_world = joint->getWorldRotation();
+
+ LLVector3 dir_world = mMotionDirectionVec * rotation_world;
+ dir_world.normalize();
+ return world * dir_world;
+}
+
+F32 LLPhysicsMotion::calculateVelocity_local(const F32 time_delta)
+{
+ LLJoint *joint = mJointState->getJoint();
+ const LLVector3 position_world = joint->getWorldPosition();
+ const LLQuaternion rotation_world = joint->getWorldRotation();
+ const LLVector3 last_position_world = mPosition_world;
+ const LLVector3 velocity_world = (position_world-last_position_world) / time_delta;
+ const F32 velocity_local = toLocal(velocity_world);
+ return velocity_local;
+}
+
+F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local,
+ const F32 time_delta)
+{
+// const F32 smoothing = getParamValue("Smoothing");
+ static const F32 smoothing = 3.0f; // Removed smoothing param since it's probably not necessary
+ const F32 acceleration_local = velocity_local - mVelocityJoint_local;
+
+ const F32 smoothed_acceleration_local =
+ acceleration_local * 1.0/smoothing +
+ mAccelerationJoint_local * (smoothing-1.0)/smoothing;
+
+ return smoothed_acceleration_local;
+}
+
+BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
+{
+ // Skip if disabled globally.
+ if (!gSavedSettings.getBOOL("AvatarPhysics"))
+ {
+ return TRUE;
+ }
+
+ BOOL update_visuals = FALSE;
+ for (motion_vec_t::iterator iter = mMotions.begin();
+ iter != mMotions.end();
+ ++iter)
+ {
+ LLPhysicsMotion *motion = (*iter);
+ update_visuals |= motion->onUpdate(time);
+ }
+
+ if (update_visuals)
+ mCharacter->updateVisualParams();
+
+ return TRUE;
+}
+
+
+// Return TRUE if character has to update visual params.
+BOOL LLPhysicsMotion::onUpdate(F32 time)
+{
+ // static FILE *mFileWrite = fopen("c:\\temp\\avatar_data.txt","w");
+
+ if (!mParamDriver)
+ return FALSE;
+
+ if (!mLastTime)
+ {
+ mLastTime = time;
+ return FALSE;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Get all parameters and settings
+ //
+
+ const F32 time_delta = time - mLastTime;
+ if (time_delta > 3.0 || time_delta <= 0.01)
+ {
+ mLastTime = time;
+ return FALSE;
+ }
+
+ // Higher LOD is better. This controls the granularity
+ // and frequency of updates for the motions.
+ const F32 lod_factor = LLVOAvatar::sPhysicsLODFactor;
+ if (lod_factor == 0)
+ {
+ return TRUE;
+ }
+
+ LLJoint *joint = mJointState->getJoint();
+
+ const F32 behavior_mass = getParamValue("Mass");
+ const F32 behavior_gravity = getParamValue("Gravity");
+ const F32 behavior_spring = getParamValue("Spring");
+ const F32 behavior_gain = getParamValue("Gain");
+ const F32 behavior_damping = getParamValue("Damping");
+ const F32 behavior_drag = getParamValue("Drag");
+ const BOOL physics_test = gSavedSettings.getBOOL("AvatarPhysicsTest") && gAgent.isGodlike();
+
+ F32 behavior_maxeffect = getParamValue("MaxEffect");
+ if (physics_test)
+ behavior_maxeffect = 1.0f;
+
+ // mPositon_local should be in normalized 0,1 range already. Just making sure...
+ F32 position_current_local = llclamp(mPosition_local,
+ 0.0f,
+ 1.0f);
+
+ // Normalize the param position to be from [0,1].
+ // We have to use normalized values because there may be more than one driven param,
+ // and each of these driven params may have its own range.
+ // This means we'll do all our calculations in normalized [0,1] local coordinates.
+ F32 position_user_local = mParamDriver->getWeight();
+ position_user_local = (position_user_local - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight());
+
+ // If the effect is turned off then don't process unless we need one more update
+ // to set the position to the default (i.e. user) position.
+ if ((behavior_maxeffect == 0) && (position_current_local == position_user_local))
+ {
+ return FALSE;
+ }
+
+ //
+ // End parameters and settings
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate velocity and acceleration in parameter space.
+ //
+
+ const F32 velocity_joint_local = calculateVelocity_local(time_delta);
+ const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local, time_delta);
+
+ //
+ // End velocity and acceleration
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate the total force
+ //
+
+ // Spring force is a restoring force towards the original user-set breast position.
+ // F = kx
+ const F32 spring_length = position_current_local - position_user_local;
+ const F32 force_spring = -spring_length * behavior_spring;
+
+ // Acceleration is the force that comes from the change in velocity of the torso.
+ // F = ma
+ const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass);
+
+ // Gravity always points downward in world space.
+ // F = mg
+ const LLVector3 gravity_world(0,0,1);
+ const F32 force_gravity = behavior_gain * (toLocal(gravity_world) * behavior_gravity * behavior_mass);
+
+ // Damping is a restoring force that opposes the current velocity.
+ // F = -kv
+ const F32 force_damping = -behavior_damping * mVelocity_local;
+
+ // Drag is a force imparted by velocity (intuitively it is similar to wind resistance)
+ // F = .5kv^2
+ const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local);
+
+ const F32 force_net = (force_accel +
+ force_gravity +
+ force_spring +
+ force_damping +
+ force_drag);
+
+ //
+ // End total force
+ ////////////////////////////////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Calculate new params
+ //
+
+ // Calculate the new acceleration based on the net force.
+ // a = F/m
+ const F32 acceleration_new_local = force_net / behavior_mass;
+ static const F32 max_acceleration = 10.0f; // magic number, used to be customizable.
+ F32 velocity_new_local = mVelocity_local + acceleration_new_local;
+ velocity_new_local = llclamp(velocity_new_local,
+ -max_acceleration, max_acceleration);
+
+ // Temporary debugging setting to cause all avatars to move, for profiling purposes.
+ if (physics_test)
+ {
+ velocity_new_local = sin(time*4.0);
+ }
+ // Calculate the new parameters, or remain unchanged if max speed is 0.
+ F32 position_new_local = position_current_local + velocity_new_local*time_delta;
+ if (behavior_maxeffect == 0)
+ position_new_local = position_user_local;
+
+ // Zero out the velocity if the param is being pushed beyond its limits.
+ if ((position_new_local < 0 && velocity_new_local < 0) ||
+ (position_new_local > 1 && velocity_new_local > 0))
+ {
+ velocity_new_local = 0;
+ }
+
+ // Check for NaN values. A NaN value is detected if the variables doesn't equal itself.
+ // If NaN, then reset everything.
+ if ((mPosition_local != mPosition_local) ||
+ (mVelocity_local != mVelocity_local) ||
+ (position_new_local != position_new_local))
+ {
+ position_new_local = 0;
+ position_current_local = 0;
+ position_user_local = 0;
+ mVelocity_local = 0;
+ mVelocityJoint_local = 0;
+ mAccelerationJoint_local = 0;
+ mPosition_local = 0;
+ mPosition_world = LLVector3(0,0,0);
+ }
+
+ const F32 position_new_local_clamped = llclamp(position_new_local,
+ 0.0f,
+ 1.0f);
+
+ LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver);
+ llassert_always(driver_param);
+ if (driver_param)
+ {
+ // If this is one of our "hidden" driver params, then make sure it's
+ // the default value.
+ if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
+ (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
+ {
+ mCharacter->setVisualParamWeight(driver_param,
+ 0,
+ FALSE);
+ }
+ for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin();
+ iter != driver_param->mDriven.end();
+ ++iter)
+ {
+ LLDrivenEntry &entry = (*iter);
+ LLViewerVisualParam *driven_param = entry.mParam;
+ setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect);
+ }
+ }
+
+ //
+ // End calculate new params
+ ////////////////////////////////////////////////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Conditionally update the visual params
+ //
+
+ // Updating the visual params (i.e. what the user sees) is fairly expensive.
+ // So only update if the params have changed enough, and also take into account
+ // the graphics LOD settings.
+
+ BOOL update_visuals = FALSE;
+
+ // For non-self, if the avatar is small enough visually, then don't update.
+ const F32 area_for_max_settings = 0.0;
+ const F32 area_for_min_settings = 1400.0;
+ const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor);
+ const F32 pixel_area = sqrtf(mCharacter->getPixelArea());
+
+ const BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(mCharacter) != NULL);
+ if ((pixel_area > area_for_this_setting) || is_self)
+ {
+ const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped);
+ const F32 min_delta = (1.01f-lod_factor)*0.4f;
+ if (llabs(position_diff_local) > min_delta)
+ {
+ update_visuals = TRUE;
+ mPositionLastUpdate_local = position_new_local;
+ }
+ }
+
+ //
+ // End update visual params
+ ////////////////////////////////////////////////////////////////////////////////
+
+ mVelocityJoint_local = velocity_joint_local;
+
+ mVelocity_local = velocity_new_local;
+ mAccelerationJoint_local = acceleration_joint_local;
+ mPosition_local = position_new_local;
+
+ mPosition_world = joint->getWorldPosition();
+ mLastTime = time;
+
+ /*
+ // Write out debugging info into a spreadsheet.
+ if (mFileWrite != NULL && is_self)
+ {
+ fprintf(mFileWrite,"%f\t%f\t%f \t\t%f \t\t%f\t%f\t%f\t \t\t%f\t%f\t%f\t%f\t%f \t\t%f\t%f\t%f\n",
+ position_new_local,
+ velocity_new_local,
+ acceleration_new_local,
+
+ time_delta,
+
+ mPosition_world[0],
+ mPosition_world[1],
+ mPosition_world[2],
+
+ force_net,
+ force_spring,
+ force_accel,
+ force_damping,
+ force_drag,
+
+ spring_length,
+ velocity_joint_local,
+ acceleration_joint_local
+ );
+ }
+ */
+
+ return update_visuals;
+}
+
+// Range of new_value_local is assumed to be [0 , 1] normalized.
+void LLPhysicsMotion::setParamValue(LLViewerVisualParam *param,
+ F32 new_value_normalized,
+ F32 behavior_maxeffect)
+{
+ const F32 value_min_local = param->getMinWeight();
+ const F32 value_max_local = param->getMaxWeight();
+ const F32 min_val = 0.5f-behavior_maxeffect/2.0;
+ const F32 max_val = 0.5f+behavior_maxeffect/2.0;
+
+ // Scale from [0,1] to [min_val,max_val]
+ const F32 new_value_rescaled = min_val + (max_val-min_val) * new_value_normalized;
+
+ // Scale from [0,1] to [value_min_local,value_max_local]
+ const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled;
+
+ mCharacter->setVisualParamWeight(param,
+ new_value_local,
+ FALSE);
+}
diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h
index 0c0087d269..b246fa99bb 100644
--- a/indra/newview/llphysicsmotion.h
+++ b/indra/newview/llphysicsmotion.h
@@ -1,124 +1,118 @@
-/**
- * @file llphysicsmotion.h
- * @brief Implementation of LLPhysicsMotion class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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$
- */
-
-#ifndef LL_LLPHYSICSMOTIONCONTROLLER_H
-#define LL_LLPHYSICSMOTIONCONTROLLER_H
-
-//-----------------------------------------------------------------------------
-// Header files
-//-----------------------------------------------------------------------------
-#include "llmotion.h"
-#include "llframetimer.h"
-
-#define PHYSICS_MOTION_FADEIN_TIME 1.0f
-#define PHYSICS_MOTION_FADEOUT_TIME 1.0f
-
-class LLPhysicsMotion;
-
-//-----------------------------------------------------------------------------
-// class LLPhysicsMotion
-//-----------------------------------------------------------------------------
-class LLPhysicsMotionController :
- public LLMotion
-{
-public:
- // Constructor
- LLPhysicsMotionController(const LLUUID &id);
-
- // Destructor
- virtual ~LLPhysicsMotionController();
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
-
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual BOOL getLoop() { return TRUE; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return PHYSICS_MOTION_FADEIN_TIME; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return PHYSICS_MOTION_FADEOUT_TIME; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea();
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character);
-
- // called when a motion is activated
- // must return TRUE to indicate success, or else
- // it will be deactivated
- virtual BOOL onActivate();
-
- // called per time step
- // must return TRUE while it is active, and
- // must return FALSE when the motion is completed.
- virtual BOOL onUpdate(F32 time, U8* joint_mask);
-
- // called when a motion is deactivated
- virtual void onDeactivate();
-
- LLCharacter* getCharacter() { return mCharacter; }
-
-protected:
- void addMotion(LLPhysicsMotion *motion);
-private:
- LLCharacter* mCharacter;
-
- typedef std::vector<LLPhysicsMotion *> motion_vec_t;
- motion_vec_t mMotions;
-};
-
-#endif // LL_LLPHYSICSMOTION_H
-
+/**
+ * @file llphysicsmotion.h
+ * @brief Implementation of LLPhysicsMotion class.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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_LLPHYSICSMOTIONCONTROLLER_H
+#define LL_LLPHYSICSMOTIONCONTROLLER_H
+
+//-----------------------------------------------------------------------------
+// Header files
+//-----------------------------------------------------------------------------
+#include "llmotion.h"
+#include "llframetimer.h"
+
+#define PHYSICS_MOTION_FADEIN_TIME 1.0f
+#define PHYSICS_MOTION_FADEOUT_TIME 1.0f
+
+class LLPhysicsMotion;
+
+//-----------------------------------------------------------------------------
+// class LLPhysicsMotion
+//-----------------------------------------------------------------------------
+class LLPhysicsMotionController :
+ public LLMotion
+{
+public:
+ // Constructor
+ LLPhysicsMotionController(const LLUUID &id);
+
+ // Destructor
+ virtual ~LLPhysicsMotionController();
+
+public:
+ //-------------------------------------------------------------------------
+ // functions to support MotionController and MotionRegistry
+ //-------------------------------------------------------------------------
+
+ // static constructor
+ // all subclasses must implement such a function and register it
+ static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); }
+
+public:
+ //-------------------------------------------------------------------------
+ // animation callbacks to be implemented by subclasses
+ //-------------------------------------------------------------------------
+
+ // motions must specify whether or not they loop
+ virtual BOOL getLoop() { return TRUE; }
+
+ // motions must report their total duration
+ virtual F32 getDuration() { return 0.0; }
+
+ // motions must report their "ease in" duration
+ virtual F32 getEaseInDuration() { return PHYSICS_MOTION_FADEIN_TIME; }
+
+ // motions must report their "ease out" duration.
+ virtual F32 getEaseOutDuration() { return PHYSICS_MOTION_FADEOUT_TIME; }
+
+ // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
+ virtual F32 getMinPixelArea();
+
+ // motions must report their priority
+ virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
+
+ virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
+
+ // run-time (post constructor) initialization,
+ // called after parameters have been set
+ // must return true to indicate success and be available for activation
+ virtual LLMotionInitStatus onInitialize(LLCharacter *character);
+
+ // called when a motion is activated
+ // must return TRUE to indicate success, or else
+ // it will be deactivated
+ virtual BOOL onActivate();
+
+ // called per time step
+ // must return TRUE while it is active, and
+ // must return FALSE when the motion is completed.
+ virtual BOOL onUpdate(F32 time, U8* joint_mask);
+
+ // called when a motion is deactivated
+ virtual void onDeactivate();
+
+ LLCharacter* getCharacter() { return mCharacter; }
+
+protected:
+ void addMotion(LLPhysicsMotion *motion);
+private:
+ LLCharacter* mCharacter;
+
+ typedef std::vector<LLPhysicsMotion *> motion_vec_t;
+ motion_vec_t mMotions;
+};
+
+#endif // LL_LLPHYSICSMOTION_H
+
diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp
index a48620bf13..cefd7df3fe 100644
--- a/indra/newview/llpolymorph.cpp
+++ b/indra/newview/llpolymorph.cpp
@@ -490,6 +490,16 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
mLastSex = avatar_sex;
+ // Check for NaN condition (NaN is detected if a variable doesn't equal itself.
+ if (mCurWeight != mCurWeight)
+ {
+ mCurWeight = 0.0;
+ }
+ if (mLastWeight != mLastWeight)
+ {
+ mLastWeight = mCurWeight+.001;
+ }
+
// perform differential update of morph
F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
// store last weight
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 78ffc7908d..20eee0d0cf 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -517,17 +517,15 @@ BOOL LLSelectMgr::removeObjectFromSelections(const LLUUID &id)
{
BOOL object_found = FALSE;
LLTool *tool = NULL;
- if (!gNoRender)
- {
- tool = LLToolMgr::getInstance()->getCurrentTool();
- // It's possible that the tool is editing an object that is not selected
- LLViewerObject* tool_editing_object = tool->getEditingObject();
- if( tool_editing_object && tool_editing_object->mID == id)
- {
- tool->stopEditing();
- object_found = TRUE;
- }
+ tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ // It's possible that the tool is editing an object that is not selected
+ LLViewerObject* tool_editing_object = tool->getEditingObject();
+ if( tool_editing_object && tool_editing_object->mID == id)
+ {
+ tool->stopEditing();
+ object_found = TRUE;
}
// Iterate through selected objects list and kill the object
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index fcd200d24a..4f18ee1da2 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -53,6 +53,8 @@
#include "llsidepanelappearance.h"
+#include "llsidetraylistener.h"
+
//#include "llscrollcontainer.h"
using namespace std;
@@ -71,6 +73,8 @@ static const std::string TAB_PANEL_CAPTION_TITLE_BOX = "sidetray_tab_title";
LLSideTray* LLSideTray::sInstance = 0;
+static LLSideTrayListener sSideTrayListener(LLSideTray::getInstance);
+
// static
LLSideTray* LLSideTray::getInstance()
{
@@ -454,6 +458,11 @@ LLSideTrayTab* LLSideTrayTab::createInstance ()
return tab;
}
+// Now that we know the definition of LLSideTrayTab, we can implement
+// tab_cast.
+template <>
+LLPanel* tab_cast<LLPanel*>(LLSideTrayTab* tab) { return tab; }
+
//////////////////////////////////////////////////////////////////////////////
// LLSideTrayButton
// Side Tray tab button with "tear off" handling.
@@ -567,6 +576,8 @@ LLSideTray::LLSideTray(const Params& params)
// register handler function to process data from the xml.
// panel_name should be specified via "parameter" attribute.
commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null));
+ commit.add("SideTray.Toggle", boost::bind(&LLSideTray::onToggleCollapse, this));
+ commit.add("SideTray.Collapse", boost::bind(&LLSideTray::collapseSideBar, this));
LLTransientFloaterMgr::getInstance()->addControlView(this);
LLView* side_bar_tabs = gViewerWindow->getRootView()->getChildView("side_bar_tabs");
if (side_bar_tabs != NULL)
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 2516b5689f..1dddd9e9bc 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -33,6 +33,13 @@
class LLAccordionCtrl;
class LLSideTrayTab;
+// Deal with LLSideTrayTab being opaque. Generic do-nothing cast...
+template <class T>
+T tab_cast(LLSideTrayTab* tab) { return tab; }
+// specialized for implementation in presence of LLSideTrayTab definition
+template <>
+LLPanel* tab_cast<LLPanel*>(LLSideTrayTab* tab);
+
// added inheritance from LLDestroyClass<LLSideTray> to enable Side Tray perform necessary actions
// while disconnecting viewer in LLAppViewer::disconnectViewer().
// LLDestroyClassList::instance().fireCallbacks() calls destroyClass method. See EXT-245.
@@ -221,6 +228,9 @@ private:
}
private:
+ // Since we provide no public way to query mTabs and mDetachedTabs, give
+ // LLSideTrayListener friend access.
+ friend class LLSideTrayListener;
LLPanel* mButtonsPanel;
typedef std::map<std::string,LLButton*> button_map_t;
button_map_t mTabButtons;
diff --git a/indra/newview/llsidetraylistener.cpp b/indra/newview/llsidetraylistener.cpp
new file mode 100644
index 0000000000..6db13e517d
--- /dev/null
+++ b/indra/newview/llsidetraylistener.cpp
@@ -0,0 +1,162 @@
+/**
+ * @file llsidetraylistener.cpp
+ * @author Nat Goodspeed
+ * @date 2011-02-15
+ * @brief Implementation for llsidetraylistener.
+ *
+ * $LicenseInfo:firstyear=2011&license=lgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "llviewerprecompiledheaders.h"
+// associated header
+#include "llsidetraylistener.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llsidetray.h"
+#include "llsdutil.h"
+
+LLSideTrayListener::LLSideTrayListener(const Getter& getter):
+ LLEventAPI("LLSideTray",
+ "Operations on side tray (e.g. query state, query tabs)"),
+ mGetter(getter)
+{
+ add("getCollapsed", "Send on [\"reply\"] an [\"open\"] Boolean",
+ &LLSideTrayListener::getCollapsed, LLSDMap("reply", LLSD()));
+ add("getTabs",
+ "Send on [\"reply\"] a map of tab names and info about them",
+ &LLSideTrayListener::getTabs, LLSDMap("reply", LLSD()));
+ add("getPanels",
+ "Send on [\"reply\"] data about panels available with SideTray.ShowPanel",
+ &LLSideTrayListener::getPanels, LLSDMap("reply", LLSD()));
+}
+
+void LLSideTrayListener::getCollapsed(const LLSD& event) const
+{
+ sendReply(LLSDMap("open", ! mGetter()->getCollapsed()), event);
+}
+
+void LLSideTrayListener::getTabs(const LLSD& event) const
+{
+ LLSD reply;
+
+ LLSideTray* tray = mGetter();
+ LLSD::Integer ord(0);
+ for (LLSideTray::child_list_const_iter_t chi(tray->beginChild()), chend(tray->endChild());
+ chi != chend; ++chi, ++ord)
+ {
+ LLView* child = *chi;
+ // How much info is important? Toss in as much as seems reasonable for
+ // each tab. But to me, at least for the moment, the most important
+ // item is the tab name.
+ LLSD info;
+ // I like the idea of returning a map keyed by tab name. But as
+ // compared to an array of maps, that loses sequence information.
+ // Address that by indicating the original order in each map entry.
+ info["ord"] = ord;
+ info["visible"] = bool(child->getVisible());
+ info["enabled"] = bool(child->getEnabled());
+ info["available"] = child->isAvailable();
+ reply[child->getName()] = info;
+ }
+
+ sendReply(reply, event);
+}
+
+static LLSD getTabInfo(LLPanel* tab)
+{
+ LLSD panels;
+ for (LLPanel::tree_iterator_t ti(tab->beginTreeDFS()), tend(tab->endTreeDFS());
+ ti != tend; ++ti)
+ {
+ // *ti is actually an LLView*, which had better not be NULL
+ LLView* view(*ti);
+ if (! view)
+ {
+ LL_ERRS("LLSideTrayListener") << "LLSideTrayTab '" << tab->getName()
+ << "' has a NULL child LLView*" << LL_ENDL;
+ }
+
+ // The logic we use to decide what "panel" names to return is heavily
+ // based on LLSideTray::showPanel(): the function that actually
+ // implements the "SideTray.ShowPanel" operation. showPanel(), in
+ // turn, depends on LLSideTray::openChildPanel(): when
+ // openChildPanel() returns non-NULL, showPanel() stops searching
+ // attached and detached LLSideTrayTab tabs.
+
+ // For each LLSideTrayTab, openChildPanel() first calls
+ // findChildView(panel_name, true). In other words, panel_name need
+ // not be a direct LLSideTrayTab child, it's sought recursively.
+ // That's why we use (begin|end)TreeDFS() in this loop.
+
+ // But this tree_iterator_t loop will actually traverse every widget
+ // in every panel. Returning all those names will not help our caller:
+ // passing most such names to openChildPanel() would not do what we
+ // want. Even though the code suggests that passing ANY valid
+ // side-panel widget name to openChildPanel() will open the tab
+ // containing that widget, results could get confusing since followup
+ // (onOpen()) logic wouldn't be invoked, and showPanel() wouldn't stop
+ // searching because openChildPanel() would return NULL.
+
+ // We must filter these LLView items, using logic that (sigh!) mirrors
+ // openChildPanel()'s own.
+
+ // openChildPanel() returns a non-NULL LLPanel* when either:
+ // - the LLView is a direct child of an LLSideTrayPanelContainer
+ // - the LLView is itself an LLPanel.
+ // But as LLSideTrayPanelContainer can directly contain LLView items
+ // that are NOT themselves LLPanels (e.g. "sidebar_me" contains an
+ // LLButton called "Jump Right Arrow"), we'd better focus only on
+ // LLSideTrayPanelContainer children that are themselves LLPanel
+ // items. Which means that the second test completely subsumes the
+ // first.
+ LLPanel* panel(dynamic_cast<LLPanel*>(view));
+ if (panel)
+ {
+ // Maybe it's overkill to construct an LLSD::Map for each panel, but
+ // the possibility remains that we might want to deliver more info
+ // about each panel than just its name.
+ panels.append(LLSDMap("name", panel->getName()));
+ }
+ }
+
+ return LLSDMap("panels", panels);
+}
+
+void LLSideTrayListener::getPanels(const LLSD& event) const
+{
+ LLSD reply;
+
+ LLSideTray* tray = mGetter();
+ // Iterate through the attached tabs.
+ LLSD::Integer ord(0);
+ for (LLSideTray::child_vector_t::const_iterator
+ ati(tray->mTabs.begin()), atend(tray->mTabs.end());
+ ati != atend; ++ati)
+ {
+ // We don't have access to LLSideTrayTab: the class definition is
+ // hidden in llsidetray.cpp. But as LLSideTrayTab isa LLPanel, use the
+ // LLPanel API. Unfortunately, without the LLSideTrayTab definition,
+ // the compiler doesn't even know this LLSideTrayTab* is an LLPanel*.
+ // Persuade it.
+ LLPanel* tab(tab_cast<LLPanel*>(*ati));
+ reply[tab->getName()] = getTabInfo(tab).with("attached", true).with("ord", ord);
+ }
+
+ // Now iterate over the detached tabs. These can also be opened via
+ // SideTray.ShowPanel.
+ ord = 0;
+ for (LLSideTray::child_vector_t::const_iterator
+ dti(tray->mDetachedTabs.begin()), dtend(tray->mDetachedTabs.end());
+ dti != dtend; ++dti)
+ {
+ LLPanel* tab(tab_cast<LLPanel*>(*dti));
+ reply[tab->getName()] = getTabInfo(tab).with("attached", false).with("ord", ord);
+ }
+
+ sendReply(reply, event);
+}
diff --git a/indra/newview/llsidetraylistener.h b/indra/newview/llsidetraylistener.h
new file mode 100644
index 0000000000..0dd2067433
--- /dev/null
+++ b/indra/newview/llsidetraylistener.h
@@ -0,0 +1,36 @@
+/**
+ * @file llsidetraylistener.h
+ * @author Nat Goodspeed
+ * @date 2011-02-15
+ * @brief
+ *
+ * $LicenseInfo:firstyear=2011&license=lgpl$
+ * Copyright (c) 2011, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_LLSIDETRAYLISTENER_H)
+#define LL_LLSIDETRAYLISTENER_H
+
+#include "lleventapi.h"
+#include <boost/function.hpp>
+
+class LLSideTray;
+class LLSD;
+
+class LLSideTrayListener: public LLEventAPI
+{
+ typedef boost::function<LLSideTray*()> Getter;
+
+public:
+ LLSideTrayListener(const Getter& getter);
+
+private:
+ void getCollapsed(const LLSD& event) const;
+ void getTabs(const LLSD& event) const;
+ void getPanels(const LLSD& event) const;
+
+ Getter mGetter;
+};
+
+#endif /* ! defined(LL_LLSIDETRAYLISTENER_H) */
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 87b33980d6..277d2430ce 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -354,11 +354,8 @@ bool idle_startup()
LLStringUtil::setLocale (LLTrans::getString(system));
- if (!gNoRender)
- {
- //note: Removing this line will cause incorrect button size in the login screen. -- bao.
- gTextureList.updateImages(0.01f) ;
- }
+ //note: Removing this line will cause incorrect button size in the login screen. -- bao.
+ gTextureList.updateImages(0.01f) ;
if ( STATE_FIRST == LLStartUp::getStartupState() )
{
@@ -673,6 +670,7 @@ bool idle_startup()
{
gUserCredential = gLoginHandler.initializeLoginInfo();
}
+ // Previous initializeLoginInfo may have generated user credentials. Re-check them.
if (gUserCredential.isNull())
{
show_connect_box = TRUE;
@@ -722,6 +720,8 @@ bool idle_startup()
timeout_count = 0;
+ initialize_edit_menu();
+
if (show_connect_box)
{
// Load all the name information out of the login view
@@ -731,15 +731,13 @@ bool idle_startup()
{
gUserCredential = gLoginHandler.initializeLoginInfo();
}
- if (gNoRender)
+ if (gHeadlessClient)
{
- LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
+ LL_WARNS("AppInit") << "Waiting at connection box in headless client. Did you mean to add autologin params?" << LL_ENDL;
}
// Make sure the process dialog doesn't hide things
gViewerWindow->setShowProgress(FALSE);
- initialize_edit_menu();
-
// Show the login dialog
login_show();
// connect dialog is already shown, so fill in the names
@@ -940,10 +938,7 @@ bool idle_startup()
gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
- if (!gNoRender)
- {
- init_start_screen(agent_location_id);
- }
+ init_start_screen(agent_location_id);
// Display the startup progress bar.
gViewerWindow->setShowProgress(TRUE);
@@ -974,11 +969,6 @@ bool idle_startup()
// Setting initial values...
LLLoginInstance* login = LLLoginInstance::getInstance();
login->setNotificationsInterface(LLNotifications::getInstance());
- if(gNoRender)
- {
- // HACK, skip optional updates if you're running drones
- login->setSkipOptionalUpdate(true);
- }
login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
login->setLastExecEvent(gLastExecEvent);
@@ -1264,14 +1254,11 @@ bool idle_startup()
gLoginMenuBarView->setVisible( FALSE );
gLoginMenuBarView->setEnabled( FALSE );
- if (!gNoRender)
- {
- // direct logging to the debug console's line buffer
- LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
-
- // set initial visibility of debug console
- gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
- }
+ // direct logging to the debug console's line buffer
+ LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
+
+ // set initial visibility of debug console
+ gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
//
// Set message handlers
@@ -1299,7 +1286,7 @@ bool idle_startup()
//gCacheName is required for nearby chat history loading
//so I just moved nearby history loading a few states further
- if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory"))
+ if (gSavedPerAccountSettings.getBOOL("LogShowHistory"))
{
LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
if (nearby_chat) nearby_chat->loadHistory();
@@ -1351,18 +1338,15 @@ bool idle_startup()
gAgentCamera.resetCamera();
// Initialize global class data needed for surfaces (i.e. textures)
- if (!gNoRender)
- {
- LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
- // Initialize all of the viewer object classes for the first time (doing things like texture fetches.
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
+ LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
+ // Initialize all of the viewer object classes for the first time (doing things like texture fetches.
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
- gSky.init(initial_sun_direction);
+ gSky.init(initial_sun_direction);
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- }
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
// For all images pre-loaded into viewer cache, decode them.
@@ -1722,46 +1706,43 @@ bool idle_startup()
LLUIColorTable::instance().saveUserSettings();
};
- if (!gNoRender)
- {
- // JC: Initializing audio requests many sounds for download.
- init_audio();
-
- // JC: Initialize "active" gestures. This may also trigger
- // many gesture downloads, if this is the user's first
- // time on this machine or -purge has been run.
- LLSD gesture_options
- = LLLoginInstance::getInstance()->getResponse("gestures");
- if (gesture_options.isDefined())
+ // JC: Initializing audio requests many sounds for download.
+ init_audio();
+
+ // JC: Initialize "active" gestures. This may also trigger
+ // many gesture downloads, if this is the user's first
+ // time on this machine or -purge has been run.
+ LLSD gesture_options
+ = LLLoginInstance::getInstance()->getResponse("gestures");
+ if (gesture_options.isDefined())
+ {
+ LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
+ << LL_ENDL;
+ uuid_vec_t item_ids;
+ for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
+ end = gesture_options.endArray(); resp_it != end; ++resp_it)
{
- LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
- << LL_ENDL;
- uuid_vec_t item_ids;
- for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
- end = gesture_options.endArray(); resp_it != end; ++resp_it)
- {
- // If the id is not specifed in the LLSD,
- // the LLSD operator[]() will return a null LLUUID.
- LLUUID item_id = (*resp_it)["item_id"];
- LLUUID asset_id = (*resp_it)["asset_id"];
+ // If the id is not specifed in the LLSD,
+ // the LLSD operator[]() will return a null LLUUID.
+ LLUUID item_id = (*resp_it)["item_id"];
+ LLUUID asset_id = (*resp_it)["asset_id"];
- if (item_id.notNull() && asset_id.notNull())
- {
- // Could schedule and delay these for later.
- const BOOL no_inform_server = FALSE;
- const BOOL no_deactivate_similar = FALSE;
- LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id,
- no_inform_server,
- no_deactivate_similar);
- // We need to fetch the inventory items for these gestures
- // so we have the names to populate the UI.
- item_ids.push_back(item_id);
- }
+ if (item_id.notNull() && asset_id.notNull())
+ {
+ // Could schedule and delay these for later.
+ const BOOL no_inform_server = FALSE;
+ const BOOL no_deactivate_similar = FALSE;
+ LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id,
+ no_inform_server,
+ no_deactivate_similar);
+ // We need to fetch the inventory items for these gestures
+ // so we have the names to populate the UI.
+ item_ids.push_back(item_id);
}
- // no need to add gesture to inventory observer, it's already made in constructor
- LLGestureMgr::instance().setFetchIDs(item_ids);
- LLGestureMgr::instance().startFetch();
}
+ // no need to add gesture to inventory observer, it's already made in constructor
+ LLGestureMgr::instance().setFetchIDs(item_ids);
+ LLGestureMgr::instance().startFetch();
}
gDisplaySwapBuffers = TRUE;
@@ -1782,13 +1763,6 @@ bool idle_startup()
// JC - 7/20/2002
gViewerWindow->sendShapeToSim();
-
- // Ignore stipend information for now. Money history is on the web site.
- // if needed, show the L$ history window
- //if (stipend_since_login && !gNoRender)
- //{
- //}
-
// The reason we show the alert is because we want to
// reduce confusion for when you log in and your provided
// location is not your expected location. So, if this is
@@ -2717,7 +2691,7 @@ bool LLStartUp::dispatchURL()
|| (dx*dx > SLOP*SLOP)
|| (dy*dy > SLOP*SLOP) )
{
- LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),
+ LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), "clicked",
NULL, false);
}
return true;
@@ -3219,7 +3193,7 @@ bool process_login_success_response()
void transition_back_to_login_panel(const std::string& emsg)
{
- if (gNoRender)
+ if (gHeadlessClient && gSavedSettings.getBOOL("AutoLogin"))
{
LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
LL_WARNS("AppInit") << emsg << LL_ENDL;
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index 6fc8153b77..bccabe21a8 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -340,11 +340,6 @@ void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction)
S32 i;
LLSurfacePatch *patchp, *neighbor_patchp;
- if (gNoRender)
- {
- return;
- }
-
mNeighbors[direction] = neighborp;
neighborp->mNeighbors[gDirOpposite[direction]] = this;
diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp
index e7b5c13860..cb49976e5f 100644
--- a/indra/newview/llsyswellwindow.cpp
+++ b/indra/newview/llsyswellwindow.cpp
@@ -310,7 +310,7 @@ void LLIMWellWindow::RowPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD&
S32 new_text_left = mChiclet->getRect().mRight + CHICLET_HPAD;
LLRect text_rect = text->getRect();
text_rect.mLeft = new_text_left;
- text->setRect(text_rect);
+ text->setShape(text_rect);
}
//---------------------------------------------------------------------------------
diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp
index dd35d5cf83..f820ae65df 100644
--- a/indra/newview/lltexturestats.cpp
+++ b/indra/newview/lltexturestats.cpp
@@ -37,7 +37,7 @@ void send_texture_stats_to_sim(const LLSD &texture_stats)
{
LLSD texture_stats_report;
// Only send stats if the agent is connected to a region.
- if (!gAgent.getRegion() || gNoRender)
+ if (!gAgent.getRegion())
{
return;
}
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 8b2f066d41..0f337825e9 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -220,7 +220,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
}
static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor");
- static LLUIColor alert_text_color = LLUIColorTable::instance().getColor("AlertTextColor");
if (mCaution)
{
LLIconCtrl* icon = LLUICtrlFactory::getInstance()->createFromFile<LLIconCtrl>("alert_icon.xml", this, LLPanel::child_registry_t::instance());
@@ -233,10 +232,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
msg_x += 32 + HPAD;
msg_box->setColor( alert_caution_text_color );
}
- else
- {
- msg_box->setColor( alert_text_color );
- }
LLRect rect;
rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() );
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index fbd6aad18f..09918c28d8 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1414,6 +1414,10 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
worn = TRUE;
}
break;
+ case LLAssetType::AT_CALLINGCARD:
+ // Calling Cards in object are disabled for now
+ // because of incomplete LSL support. See STORM-1117.
+ return ACCEPT_NO;
default:
break;
}
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 9549f180df..95bd210ae3 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -37,7 +37,7 @@
#include "llavatarnamecache.h"
#include "llviewercontrol.h"
#include "llfocusmgr.h"
-//#include "llfirstuse.h"
+#include "llfirstuse.h"
#include "llfloaterland.h"
#include "llfloaterreg.h"
#include "llfloaterscriptdebug.h"
@@ -528,42 +528,17 @@ void LLToolPie::selectionPropertiesReceived()
BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
{
- if (!mMouseOutsideSlop
- && mMouseButtonDown
- && gSavedSettings.getBOOL("ClickToWalk"))
- {
- S32 delta_x = x - mMouseDownX;
- S32 delta_y = y - mMouseDownY;
- S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold");
- if (delta_x * delta_x + delta_y * delta_y > threshold * threshold)
- {
- startCameraSteering();
- }
- }
-
mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE);
-
- if (inCameraSteerMode())
- {
- steerCameraWithMouse(x, y);
- gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
- return TRUE;
- }
-
- // perform a separate pick that detects transparent objects since they respond to 1-click actions
- LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE);
-
- // Show screen-space highlight glow effect
- bool show_highlight = false;
LLViewerObject *parent = NULL;
LLViewerObject *object = mHoverPick.getObject();
-
if (object)
{
parent = object->getRootEdit();
}
- LLViewerObject* click_action_object = click_action_pick.getObject();
+ // Show screen-space highlight glow effect
+ bool show_highlight = false;
+
if (handleMediaHover(mHoverPick))
{
// *NOTE: If you think the hover glow conflicts with the media outline, you
@@ -572,39 +547,70 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
// cursor set by media object
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
}
- else if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit()))
+ else if (!mMouseOutsideSlop
+ && mMouseButtonDown
+ && gSavedSettings.getBOOL("ClickToWalk"))
{
- show_highlight = true;
- ECursorType cursor = cursorFromObject(click_action_object);
- gViewerWindow->setCursor(cursor);
- lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
+ S32 delta_x = x - mMouseDownX;
+ S32 delta_y = y - mMouseDownY;
+ S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold");
+ if (delta_x * delta_x + delta_y * delta_y > threshold * threshold)
+ {
+ startCameraSteering();
+ steerCameraWithMouse(x, y);
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ }
+ else
+ {
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ }
}
-
- else if ((object && !object->isAvatar() && object->usePhysics())
- || (parent && !parent->isAvatar() && parent->usePhysics()))
+ else if (inCameraSteerMode())
{
- show_highlight = true;
+ steerCameraWithMouse(x, y);
gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
- lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
- }
- else if ( (object && object->flagHandleTouch())
- || (parent && parent->flagHandleTouch()))
- {
- show_highlight = true;
- gViewerWindow->setCursor(UI_CURSOR_HAND);
- lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
}
else
{
- gViewerWindow->setCursor(UI_CURSOR_ARROW);
- lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
+ // perform a separate pick that detects transparent objects since they respond to 1-click actions
+ LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE);
+
+ LLViewerObject* click_action_object = click_action_pick.getObject();
- if(!object)
+ if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit()))
+ {
+ show_highlight = true;
+ ECursorType cursor = cursorFromObject(click_action_object);
+ gViewerWindow->setCursor(cursor);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
+ }
+
+ else if ((object && !object->isAvatar() && object->usePhysics())
+ || (parent && !parent->isAvatar() && parent->usePhysics()))
+ {
+ show_highlight = true;
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
+ }
+ else if ( (object && object->flagHandleTouch())
+ || (parent && parent->flagHandleTouch()))
+ {
+ show_highlight = true;
+ gViewerWindow->setCursor(UI_CURSOR_HAND);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
+ }
+ else
{
- LLViewerMediaFocus::getInstance()->clearHover();
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
}
}
+ if(!object)
+ {
+ LLViewerMediaFocus::getInstance()->clearHover();
+ }
+
static LLCachedControl<bool> enable_highlight(
gSavedSettings, "RenderHoverGlowEnable", false);
LLDrawable* drawable = NULL;
@@ -662,6 +668,8 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
mAutoPilotDestination->setDuration(3.f);
handle_go_to();
+ LLFirstUse::notMoving(false);
+
mBlockClickToWalk = false;
return TRUE;
@@ -1430,6 +1438,7 @@ bool LLToolPie::handleMediaClick(const LLPickInfo& pick)
{
// Make sure keyboard focus is set to the media focus object.
gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance());
+ LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl();
media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE));
mMediaMouseCaptureID = mep->getMediaID();
@@ -1709,8 +1718,13 @@ void LLToolPie::showVisualContextMenuEffect()
effectp->setDuration(0.25f);
}
+typedef enum e_near_far
+{
+ NEAR_INTERSECTION,
+ FAR_INTERSECTION
+} ENearFar;
-bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, LLVector3& intersection_pt)
+bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, e_near_far near_far, LLVector3& intersection_pt)
{
// do ray/sphere intersection by solving quadratic equation
LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center;
@@ -1718,10 +1732,11 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di
F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
F32 discriminant = B*B - 4.f*C;
- if (discriminant > 0.f)
+ if (discriminant >= 0.f)
{ // intersection detected, now find closest one
F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
- if (t0 > 0.f)
+
+ if (t0 > 0.f && near_far == NEAR_INTERSECTION)
{
intersection_pt = ray_pt + ray_dir * t0;
}
@@ -1732,12 +1747,15 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di
}
return true;
}
-
- return false;
+ else
+ { // no intersection
+ return false;
+ }
}
void LLToolPie::startCameraSteering()
{
+ LLFirstUse::notMoving(false);
mMouseOutsideSlop = true;
mBlockClickToWalk = true;
@@ -1786,64 +1804,80 @@ void LLToolPie::startCameraSteering()
void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
{
- const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f;
-
+ const LLViewerCamera& camera = LLViewerCamera::instance();
+ const LLCoordFrame& rotation_frame = gAgent.getFrameAgent();
const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal);
- const LLVector3 rotation_center = gAgent.getFrameAgent().getOrigin();
- // FIXME: get this to work with camera tilt (i.e. sitting on a rotating object)
- const LLVector3 rotation_up_axis(LLVector3::z_axis);
-
- LLVector3 object_rotation_center = rotation_center + parallel_component(pick_pos - rotation_center, rotation_up_axis);
- F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(rotation_center, LLViewerCamera::instance().getOrigin());;
- F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, object_rotation_center), min_rotation_radius, F32_MAX);
+ const LLVector3 pick_rotation_center = rotation_frame.getOrigin() + parallel_component(pick_pos - rotation_frame.getOrigin(), rotation_frame.getUpAxis());
+ const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f;
+ const F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(pick_rotation_center, camera.getOrigin());;
+ const F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, pick_rotation_center), min_rotation_radius, F32_MAX);
+ const LLVector3 camera_to_rotation_center = pick_rotation_center - camera.getOrigin();
+ const LLVector3 adjusted_camera_pos = LLViewerCamera::instance().getOrigin() + projected_vec(camera_to_rotation_center, rotation_frame.getUpAxis());
+ const F32 camera_distance_from_rotation_center = dist_vec(adjusted_camera_pos, pick_rotation_center);
- LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_up_axis);
+ LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_frame.getUpAxis());
mouse_ray.normalize();
- LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_up_axis);
+ LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_frame.getUpAxis());
old_mouse_ray.normalize();
- LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
- LLVector3 camera_to_rotation_center = object_rotation_center - camera_pos;
- LLVector3 adjusted_camera_pos = camera_pos + projected_vec(camera_to_rotation_center, rotation_up_axis);
- LLVector3 rotation_fwd_axis = LLViewerCamera::instance().getAtAxis() - projected_vec(LLViewerCamera::instance().getAtAxis(), rotation_up_axis);
- rotation_fwd_axis.normalize();
- F32 pick_dist = dist_vec(pick_pos, adjusted_camera_pos);
-
+ F32 yaw_angle;
+ F32 old_yaw_angle;
LLVector3 mouse_on_sphere;
- bool mouse_hit_sphere = intersect_ray_with_sphere(adjusted_camera_pos + (mouse_ray * pick_dist * 1.1f),
- -1.f * mouse_ray,
- object_rotation_center,
- pick_distance_from_rotation_center,
- mouse_on_sphere);
-
LLVector3 old_mouse_on_sphere;
- intersect_ray_with_sphere(adjusted_camera_pos + (old_mouse_ray * pick_dist * 1.1f),
- -1.f * old_mouse_ray,
- object_rotation_center,
- pick_distance_from_rotation_center,
- old_mouse_on_sphere);
- if (mouse_hit_sphere)
+ if (intersect_ray_with_sphere(
+ adjusted_camera_pos,
+ mouse_ray,
+ pick_rotation_center,
+ pick_distance_from_rotation_center,
+ FAR_INTERSECTION,
+ mouse_on_sphere))
{
- // calculate rotation frame in screen space
- LLVector3 screen_rotation_up_axis = orthogonal_component(rotation_up_axis, LLViewerCamera::instance().getAtAxis());
- screen_rotation_up_axis.normalize();
-
- LLVector3 screen_rotation_left_axis = screen_rotation_up_axis % LLViewerCamera::instance().getAtAxis();
+ LLVector3 mouse_sphere_offset = mouse_on_sphere - pick_rotation_center;
+ yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis());
+ }
+ else
+ {
+ yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center);
+ if (mouse_ray * rotation_frame.getLeftAxis() < 0.f)
+ {
+ yaw_angle *= -1.f;
+ }
+ }
- LLVector3 rotation_furthest_pt = object_rotation_center + pick_distance_from_rotation_center * rotation_fwd_axis;
- F32 mouse_lateral_distance = llclamp(((mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
- F32 old_mouse_lateral_distance = llclamp(((old_mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
+ if (intersect_ray_with_sphere(
+ adjusted_camera_pos,
+ old_mouse_ray,
+ pick_rotation_center,
+ pick_distance_from_rotation_center,
+ FAR_INTERSECTION,
+ old_mouse_on_sphere))
+ {
+ LLVector3 mouse_sphere_offset = old_mouse_on_sphere - pick_rotation_center;
+ old_yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis());
+ }
+ else
+ {
+ old_yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center);
- F32 yaw_angle = asinf(mouse_lateral_distance);
- F32 old_yaw_angle = asinf(old_mouse_lateral_distance);
+ if (mouse_ray * rotation_frame.getLeftAxis() < 0.f)
+ {
+ old_yaw_angle *= -1.f;
+ }
+ }
- F32 delta_angle = yaw_angle - old_yaw_angle;
- if (!mClockwise) delta_angle *= -1.f;
+ const F32 delta_angle = yaw_angle - old_yaw_angle;
+ if (mClockwise)
+ {
gAgent.yaw(delta_angle);
- mMouseSteerX = x;
- mMouseSteerY = y;
}
+ else
+ {
+ gAgent.yaw(-delta_angle);
+ }
+
+ mMouseSteerX = x;
+ mMouseSteerY = y;
}
diff --git a/indra/newview/lluilistener.cpp b/indra/newview/lluilistener.cpp
index 4d6eac4958..6b2cd71d40 100644
--- a/indra/newview/lluilistener.cpp
+++ b/indra/newview/lluilistener.cpp
@@ -34,9 +34,11 @@
// std headers
// external library headers
// other Linden headers
+#include "llui.h" // getRootView(), resolvePath()
#include "lluictrl.h"
#include "llerror.h"
+
LLUIListener::LLUIListener():
LLEventAPI("UI",
"LLUICtrl::CommitCallbackRegistry listener.\n"
@@ -47,6 +49,12 @@ LLUIListener::LLUIListener():
"as if from a user gesture on a menu -- or a button click.",
&LLUIListener::call,
LLSD().with("function", LLSD()));
+
+ add("getValue",
+ "For the UI control identified by the path in [\"path\"], return the control's\n"
+ "current value as [\"value\"] reply.",
+ &LLUIListener::getValue,
+ LLSDMap("path", LLSD())("reply", LLSD()));
}
void LLUIListener::call(const LLSD& event) const
@@ -71,3 +79,23 @@ void LLUIListener::call(const LLSD& event) const
(*func)(NULL, event["parameter"]);
}
}
+
+void LLUIListener::getValue(const LLSD&event) const
+{
+ LLSD reply = LLSD::emptyMap();
+
+ const LLView* root = LLUI::getRootView();
+ const LLView* view = LLUI::resolvePath(root, event["path"].asString());
+ const LLUICtrl* ctrl(dynamic_cast<const LLUICtrl*>(view));
+
+ if (ctrl)
+ {
+ reply["value"] = ctrl->getValue();
+ }
+ else
+ {
+ // *TODO: ??? return something indicating failure to resolve
+ }
+
+ sendReply(reply, event);
+}
diff --git a/indra/newview/lluilistener.h b/indra/newview/lluilistener.h
index e7847f01e8..08724024dc 100644
--- a/indra/newview/lluilistener.h
+++ b/indra/newview/lluilistener.h
@@ -41,6 +41,7 @@ public:
private:
void call(const LLSD& event) const;
+ void getValue(const LLSD&event) const;
};
#endif /* ! defined(LL_LLUILISTENER_H) */
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index ebbb045f0a..ed4d278e90 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -53,6 +53,7 @@ class LLURLDispatcherImpl
{
public:
static bool dispatch(const LLSLURL& slurl,
+ const std::string& nav_type,
LLMediaCtrl* web,
bool trusted_browser);
// returns true if handled or explicitly blocked.
@@ -61,6 +62,7 @@ public:
private:
static bool dispatchCore(const LLSLURL& slurl,
+ const std::string& nav_type,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser);
@@ -71,6 +73,7 @@ private:
// Returns true if handled.
static bool dispatchApp(const LLSLURL& slurl,
+ const std::string& nav_type,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser);
@@ -78,7 +81,7 @@ private:
// by showing panel in Search floater.
// Returns true if handled or explicitly blocked.
- static bool dispatchRegion(const LLSLURL& slurl, bool right_mouse);
+ static bool dispatchRegion(const LLSLURL& slurl, const std::string& nav_type, bool right_mouse);
// handles secondlife://Ahern/123/45/67/
// Returns true if handled.
@@ -97,6 +100,7 @@ private:
// static
bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
+ const std::string& nav_type,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser)
@@ -105,9 +109,9 @@ bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
switch(slurl.getType())
{
case LLSLURL::APP:
- return dispatchApp(slurl, right_mouse, web, trusted_browser);
+ return dispatchApp(slurl, nav_type, right_mouse, web, trusted_browser);
case LLSLURL::LOCATION:
- return dispatchRegion(slurl, right_mouse);
+ return dispatchRegion(slurl, nav_type, right_mouse);
default:
return false;
}
@@ -122,11 +126,12 @@ bool LLURLDispatcherImpl::dispatchCore(const LLSLURL& slurl,
// static
bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl,
+ const std::string& nav_type,
LLMediaCtrl* web,
bool trusted_browser)
{
const bool right_click = false;
- return dispatchCore(slurl, right_click, web, trusted_browser);
+ return dispatchCore(slurl, nav_type, right_click, web, trusted_browser);
}
// static
@@ -135,11 +140,12 @@ bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl)
const bool right_click = true;
LLMediaCtrl* web = NULL;
const bool trusted_browser = false;
- return dispatchCore(slurl, right_click, web, trusted_browser);
+ return dispatchCore(slurl, "clicked", right_click, web, trusted_browser);
}
// static
bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
+ const std::string& nav_type,
bool right_mouse,
LLMediaCtrl* web,
bool trusted_browser)
@@ -147,7 +153,7 @@ bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
llinfos << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << llendl;
const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery());
bool handled = LLCommandDispatcher::dispatch(
- slurl.getAppCmd(), slurl.getAppPath(), query_map, web, trusted_browser);
+ slurl.getAppCmd(), slurl.getAppPath(), query_map, web, nav_type, trusted_browser);
// alert if we didn't handle this secondlife:///app/ SLURL
// (but still return true because it is a valid app SLURL)
@@ -159,7 +165,7 @@ bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl,
}
// static
-bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, bool right_mouse)
+bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string& nav_type, bool right_mouse)
{
if(slurl.getType() != LLSLURL::LOCATION)
{
@@ -287,10 +293,11 @@ LLTeleportHandler gTeleportHandler;
// static
bool LLURLDispatcher::dispatch(const std::string& slurl,
+ const std::string& nav_type,
LLMediaCtrl* web,
bool trusted_browser)
{
- return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser);
+ return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), nav_type, web, trusted_browser);
}
// static
@@ -310,7 +317,7 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl)
// *TODO: Make this trust model more refined. JC
const bool trusted_browser = true;
LLMediaCtrl* web = NULL;
- return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), web, trusted_browser);
+ return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_browser);
}
diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h
index b07db4da3f..6309a97af5 100644
--- a/indra/newview/llurldispatcher.h
+++ b/indra/newview/llurldispatcher.h
@@ -33,6 +33,7 @@ class LLURLDispatcher
public:
static bool dispatch(const std::string& slurl,
+ const std::string& nav_type,
LLMediaCtrl* web,
bool trusted_browser);
// At startup time and on clicks in internal web browsers,
@@ -41,6 +42,8 @@ public:
// secondlife://RegionName/123/45/67/
// secondlife:///app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show
// sl://app/foo/bar
+ // @param nav_type
+ // type of navigation type (see LLQtWebKit::LLWebPage::acceptNavigationRequest)
// @param web
// Pointer to LLMediaCtrl sending URL, can be NULL
// @param trusted_browser
diff --git a/indra/newview/llurldispatcherlistener.cpp b/indra/newview/llurldispatcherlistener.cpp
index d0441d7bfa..c7b9afafef 100644
--- a/indra/newview/llurldispatcherlistener.cpp
+++ b/indra/newview/llurldispatcherlistener.cpp
@@ -61,7 +61,7 @@ void LLURLDispatcherListener::dispatch(const LLSD& params) const
// But for testing, allow a caller to specify untrusted.
trusted_browser = params["trusted"].asBoolean();
}
- LLURLDispatcher::dispatch(params["url"], NULL, trusted_browser);
+ LLURLDispatcher::dispatch(params["url"], "clicked", NULL, trusted_browser);
}
void LLURLDispatcherListener::dispatchRightClick(const LLSD& params) const
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index ba48ad4517..a60d7e0793 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1,1507 +1,1507 @@
-/**
- * @file llviewerdisplay.cpp
- * @brief LLViewerDisplay class implementation
- *
- * $LicenseInfo:firstyear=2004&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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llviewerdisplay.h"
-
-#include "llgl.h"
-#include "llrender.h"
-#include "llglheaders.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llviewercontrol.h"
-#include "llcoord.h"
-#include "llcriticaldamp.h"
-#include "lldir.h"
-#include "lldynamictexture.h"
-#include "lldrawpoolalpha.h"
-#include "llfeaturemanager.h"
-//#include "llfirstuse.h"
-#include "llhudmanager.h"
-#include "llimagebmp.h"
-#include "llmemory.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "llstartup.h"
-#include "lltoolfocus.h"
-#include "lltoolmgr.h"
-#include "lltooldraganddrop.h"
-#include "lltoolpie.h"
-#include "lltracker.h"
-#include "lltrans.h"
-#include "llui.h"
-#include "llviewercamera.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerwindow.h"
-#include "llvoavatarself.h"
-#include "llvograss.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "llspatialpartition.h"
-#include "llappviewer.h"
-#include "llstartup.h"
-#include "llviewershadermgr.h"
-#include "llfasttimer.h"
-#include "llfloatertools.h"
-#include "llviewertexturelist.h"
-#include "llfocusmgr.h"
-#include "llcubemap.h"
-#include "llviewerregion.h"
-#include "lldrawpoolwater.h"
-#include "lldrawpoolbump.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llpostprocess.h"
-
-extern LLPointer<LLViewerTexture> gStartTexture;
-
-LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
-
-// used to toggle renderer back on after teleport
-const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain
-const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
-const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport.
-BOOL gTeleportDisplay = FALSE;
-LLFrameTimer gTeleportDisplayTimer;
-LLFrameTimer gTeleportArrivalTimer;
-const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
-
-BOOL gForceRenderLandFence = FALSE;
-BOOL gDisplaySwapBuffers = FALSE;
-BOOL gDepthDirty = FALSE;
-BOOL gResizeScreenTexture = FALSE;
-BOOL gWindowResized = FALSE;
-BOOL gSnapshot = FALSE;
-
-U32 gRecentFrameCount = 0; // number of 'recent' frames
-LLFrameTimer gRecentFPSTime;
-LLFrameTimer gRecentMemoryTime;
-
-// Rendering stuff
-void pre_show_depth_buffer();
-void post_show_depth_buffer();
-void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
-void render_hud_attachments();
-void render_ui_3d();
-void render_ui_2d();
-void render_disconnected_background();
-
-void display_startup()
-{
- if ( !gViewerWindow->getActive()
- || !gViewerWindow->mWindow->getVisible()
- || gViewerWindow->mWindow->getMinimized()
- || gNoRender )
- {
- return;
- }
-
- gPipeline.updateGL();
-
- // Update images?
- //gImageList.updateImages(0.01f);
-
- LLGLSDefault gls_default;
-
- // Required for HTML update in login screen
- static S32 frame_count = 0;
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- if (frame_count++ > 1) // make sure we have rendered a frame first
- {
- LLViewerDynamicTexture::updateAllInstances();
- }
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- LLGLSUIDefault gls_ui;
- gPipeline.disableLights();
-
- gViewerWindow->setup2DRender();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- gGL.color4f(1,1,1,1);
- gViewerWindow->draw();
- gGL.flush();
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- gViewerWindow->mWindow->swapBuffers();
- glClear(GL_DEPTH_BUFFER_BIT);
-}
-
-void display_update_camera()
-{
- LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
- // TODO: cut draw distance down if customizing avatar?
- // TODO: cut draw distance on per-parcel basis?
-
- // Cut draw distance in half when customizing avatar,
- // but on the viewer only.
- F32 final_far = gAgentCamera.mDrawDistance;
- if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
- {
- final_far *= 0.5f;
- }
- LLViewerCamera::getInstance()->setFar(final_far);
- gViewerWindow->setup3DRender();
-
- // update all the sky/atmospheric/water settings
- LLWLParamManager::instance()->update(LLViewerCamera::getInstance());
- LLWaterParamManager::instance()->update(LLViewerCamera::getInstance());
-
- // Update land visibility too
- LLWorld::getInstance()->setLandFarClip(final_far);
-}
-
-// Write some stats to llinfos
-void display_stats()
-{
- F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
- if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
- {
- F32 fps = gRecentFrameCount / fps_log_freq;
- llinfos << llformat("FPS: %.02f", fps) << llendl;
- gRecentFrameCount = 0;
- gRecentFPSTime.reset();
- }
- F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
- if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
- {
- gMemoryAllocated = LLMemory::getCurrentRSS();
- U32 memory = (U32)(gMemoryAllocated / (1024*1024));
- llinfos << llformat("MEMORY: %d MB", memory) << llendl;
- gRecentMemoryTime.reset();
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_PICK("Picking");
-static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
-static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
-static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
-
-// Paint the display!
-void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
-{
- LLMemType mt_render(LLMemType::MTYPE_RENDER);
- LLFastTimer t(FTM_RENDER);
-
- if (gWindowResized)
- { //skip render on frames where window has been resized
- gGL.flush();
- glClear(GL_COLOR_BUFFER_BIT);
- gViewerWindow->mWindow->swapBuffers();
- gPipeline.resizeScreenTexture();
- gResizeScreenTexture = FALSE;
- gWindowResized = FALSE;
- return;
- }
-
- if (LLPipeline::sRenderDeferred)
- { //hack to make sky show up in deferred snapshots
- for_snapshot = FALSE;
- }
-
- if (LLPipeline::sRenderFrameTest)
- {
- send_agent_pause();
- }
-
- gSnapshot = for_snapshot;
-
- LLGLSDefault gls_default;
- LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- stop_glerror();
-
- gPipeline.disableLights();
-
- stop_glerror();
-
- // Don't draw if the window is hidden or minimized.
- // In fact, must explicitly check the minimized state before drawing.
- // Attempting to draw into a minimized window causes a GL error. JC
- if ( !gViewerWindow->getActive()
- || !gViewerWindow->mWindow->getVisible()
- || gViewerWindow->mWindow->getMinimized() )
- {
- // Clean up memory the pools may have allocated
- if (rebuild)
- {
- stop_glerror();
- gPipeline.rebuildPools();
- stop_glerror();
- }
-
- stop_glerror();
- gViewerWindow->returnEmptyPicks();
- stop_glerror();
- return;
- }
-
- gViewerWindow->checkSettings();
-
- {
- LLFastTimer ftm(FTM_PICK);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Pick");
- gViewerWindow->performPick();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- //////////////////////////////////////////////////////////
- //
- // Logic for forcing window updates if we're in drone mode.
- //
-
- if (gNoRender)
- {
-#if LL_WINDOWS
- static F32 last_update_time = 0.f;
- if ((gFrameTimeSeconds - last_update_time) > 1.f)
- {
- InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE);
- last_update_time = gFrameTimeSeconds;
- }
-#elif LL_DARWIN
- // MBW -- Do something clever here.
-#endif
- // Not actually rendering, don't bother.
- return;
- }
-
-
- //
- // Bail out if we're in the startup state and don't want to try to
- // render the world.
- //
- if (LLStartUp::getStartupState() < STATE_STARTED)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
- display_startup();
- return;
- }
-
- //LLGLState::verify(FALSE);
-
- /////////////////////////////////////////////////
- //
- // Update GL Texture statistics (used for discard logic?)
- //
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
- stop_glerror();
-
- LLImageGL::updateStats(gFrameTimeSeconds);
-
- LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
- LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
-
- gPipeline.mBackfaceCull = TRUE;
- gFrameCount++;
- gRecentFrameCount++;
- if (gFocusMgr.getAppHasFocus())
- {
- gForegroundFrameCount++;
- }
-
- //////////////////////////////////////////////////////////
- //
- // Display start screen if we're teleporting, and skip render
- //
-
- if (gTeleportDisplay)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
- const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
-
- S32 attach_count = 0;
- if (isAgentAvatarValid())
- {
- attach_count = gAgentAvatarp->getAttachmentCount();
- }
- F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
- F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
- F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
- if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) )
- {
- // Give up. Don't keep the UI locked forever.
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- gAgent.setTeleportMessage(std::string());
- }
-
- const std::string& message = gAgent.getTeleportMessage();
- switch( gAgent.getTeleportState() )
- {
- case LLAgent::TELEPORT_START:
- // Transition to REQUESTED. Viewer has sent some kind
- // of TeleportRequest to the source simulator
- gTeleportDisplayTimer.reset();
- gViewerWindow->setShowProgress(TRUE);
- gViewerWindow->setProgressPercent(0);
- gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED );
- gAgent.setTeleportMessage(
- LLAgent::sTeleportProgressMessages["requesting"]);
- break;
-
- case LLAgent::TELEPORT_REQUESTED:
- // Waiting for source simulator to respond
- gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) );
- gViewerWindow->setProgressString(message);
- break;
-
- case LLAgent::TELEPORT_MOVING:
- // Viewer has received destination location from source simulator
- gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) );
- gViewerWindow->setProgressString(message);
- break;
-
- case LLAgent::TELEPORT_START_ARRIVAL:
- // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator
- gTeleportArrivalTimer.reset();
- gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
- gViewerWindow->setProgressPercent(75.f);
- gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING );
- gAgent.setTeleportMessage(
- LLAgent::sTeleportProgressMessages["arriving"]);
- gTextureList.mForceResetTextureStats = TRUE;
- gAgentCamera.resetView(TRUE, TRUE);
- break;
-
- case LLAgent::TELEPORT_ARRIVING:
- // Make the user wait while content "pre-caches"
- {
- F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY);
- if( arrival_fraction > 1.f )
- {
- arrival_fraction = 1.f;
- //LLFirstUse::useTeleport();
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- }
- gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
- gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f);
- gViewerWindow->setProgressString(message);
- }
- break;
-
- case LLAgent::TELEPORT_LOCAL:
- // Short delay when teleporting in the same sim (progress screen active but not shown - did not
- // fall-through from TELEPORT_START)
- {
- if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY )
- {
- //LLFirstUse::useTeleport();
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
- }
- }
- break;
-
- case LLAgent::TELEPORT_NONE:
- // No teleport in progress
- gViewerWindow->setShowProgress(FALSE);
- gTeleportDisplay = FALSE;
- break;
- }
- }
- else if(LLAppViewer::instance()->logoutRequestSent())
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
- F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
- if (percent_done > 100.f)
- {
- percent_done = 100.f;
- }
-
- if( LLApp::isExiting() )
- {
- percent_done = 100.f;
- }
-
- gViewerWindow->setProgressPercent( percent_done );
- }
- else
- if (gRestoreGL)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
- F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
- if( percent_done > 100.f )
- {
- gViewerWindow->setShowProgress(FALSE);
- gRestoreGL = FALSE;
- }
- else
- {
-
- if( LLApp::isExiting() )
- {
- percent_done = 100.f;
- }
-
- gViewerWindow->setProgressPercent( percent_done );
- }
- }
-
- //////////////////////////
- //
- // Prepare for the next frame
- //
-
- /////////////////////////////
- //
- // Update the camera
- //
- //
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
- LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
- LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
-
- //////////////////////////
- //
- // clear the next buffer
- // (must follow dynamic texture writing since that uses the frame buffer)
- //
-
- if (gDisconnected)
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
- render_ui();
- }
-
- //////////////////////////
- //
- // Set rendering options
- //
- //
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
- stop_glerror();
-
- ///////////////////////////////////////
- //
- // Slam lighting parameters back to our defaults.
- // Note that these are not the same as GL defaults...
-
- stop_glerror();
- F32 one[4] = {1.f, 1.f, 1.f, 1.f};
- glLightModelfv (GL_LIGHT_MODEL_AMBIENT,one);
- stop_glerror();
-
- /////////////////////////////////////
- //
- // Render
- //
- // Actually push all of our triangles to the screen.
- //
-
- // do render-to-texture stuff here
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
- {
- LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
- LLFastTimer t(FTM_UPDATE_TEXTURES);
- if (LLViewerDynamicTexture::updateAllInstances())
- {
- gGL.setColorMask(true, true);
- glClear(GL_DEPTH_BUFFER_BIT);
- }
- }
-
- gViewerWindow->setup3DViewport();
-
- gPipeline.resetFrameStats(); // Reset per-frame statistics.
-
- if (!gDisconnected)
- {
- LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- { //don't draw hud objects in this frame
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
-
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
- { //don't draw hud particles in this frame
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
- }
-
- //upkeep gl name pools
- LLGLNamePool::upkeepPools();
-
- stop_glerror();
- display_update_camera();
- stop_glerror();
-
- // *TODO: merge these two methods
- {
- LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- stop_glerror();
- }
-
- {
- LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
- const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
- gPipeline.createObjects(max_geom_update_time);
- gPipeline.updateGeom(max_geom_update_time);
- stop_glerror();
- }
-
- gPipeline.updateGL();
- stop_glerror();
-
- S32 water_clip = 0;
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
- (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
- gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
- {
- if (LLViewerCamera::getInstance()->cameraUnderWater())
- {
- water_clip = -1;
- }
- else
- {
- water_clip = 1;
- }
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
-
- //Increment drawable frame counter
- LLDrawable::incrementVisible();
-
- LLSpatialGroup::sNoDelete = TRUE;
- LLPipeline::sUseOcclusion =
- (!gUseWireframe
- && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")
- && gSavedSettings.getBOOL("UseOcclusion")
- && gGLManager.mHasOcclusionQuery) ? 2 : 0;
-
- /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
- { //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
- LLPipeline::sUseOcclusion = 3;
- }*/
-
- LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred");
- LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred");
- LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
- LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
- LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
-
- S32 occlusion = LLPipeline::sUseOcclusion;
- if (gDepthDirty)
- { //depth buffer is invalid, don't overwrite occlusion state
- LLPipeline::sUseOcclusion = llmin(occlusion, 1);
- }
- gDepthDirty = FALSE;
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- static LLCullResult result;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
- stop_glerror();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- BOOL to_texture = gPipeline.canUseVertexShaders() &&
- LLPipeline::sRenderGlow;
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
-
- {
- LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP);
- {
- LLFastTimer ftm(FTM_CLIENT_COPY);
- LLVertexBuffer::clientCopy(0.016);
- }
-
- if (gResizeScreenTexture)
- {
- gResizeScreenTexture = FALSE;
- gPipeline.resizeScreenTexture();
- }
-
- gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- if (!for_snapshot)
- {
- if (gFrameCount > 1)
- { //for some reason, ATI 4800 series will error out if you
- //try to generate a shadow before the first frame is through
- gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
- }
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- glh::matrix4f proj = glh_get_current_projection();
- glh::matrix4f mod = glh_get_current_modelview();
- glViewport(0,0,512,512);
- LLVOAvatar::updateFreezeCounter() ;
- LLVOAvatar::updateImpostors();
-
- glh_set_current_projection(proj);
- glh_set_current_modelview(mod);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(proj.m);
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(mod.m);
- gViewerWindow->setup3DViewport();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- }
- glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
-
- //if (!for_snapshot)
- {
- LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
- gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
- gPipeline.generateHighlight(*LLViewerCamera::getInstance());
- }
-
- //////////////////////////////////////
- //
- // Update images, using the image stats generated during object update/culling
- //
- // Can put objects onto the retextured list.
- //
- // Doing this here gives hardware occlusion queries extra time to complete
- LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
-
- {
- LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
- LLFastTimer t(FTM_IMAGE_UPDATE);
-
- LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(),
- LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean());
-
- gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
-
- F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
- max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
- gTextureList.updateImages(max_image_decode_time);
-
- //remove dead textures from GL
- LLImageGL::deleteDeadTextures();
- stop_glerror();
- }
- ///////////////////////////////////
- //
- // StateSort
- //
- // Responsible for taking visible objects, and adding them to the appropriate draw orders.
- // In the case of alpha objects, z-sorts them first.
- // Also creates special lists for outlines and selected face rendering.
- //
- LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
- {
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
- gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
- stop_glerror();
-
- if (rebuild)
- {
- //////////////////////////////////////
- //
- // rebuildPools
- //
- //
- gPipeline.rebuildPools();
- stop_glerror();
- }
- }
-
- LLPipeline::sUseOcclusion = occlusion;
-
- {
- LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY);
- LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
- LLFastTimer t(FTM_UPDATE_SKY);
- gSky.updateSky();
- }
-
- if(gUseWireframe)
- {
- glClearColor(0.5f, 0.5f, 0.5f, 0.f);
- glClear(GL_COLOR_BUFFER_BIT);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
-
- //// render frontmost floater opaque for occlusion culling purposes
- //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
- //// assumes frontmost floater with focus is opaque
- //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
- //{
- // glMatrixMode(GL_MODELVIEW);
- // glPushMatrix();
- // {
- // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
- // glLoadIdentity();
-
- // LLRect floater_rect = frontmost_floaterp->calcScreenRect();
- // // deflate by one pixel so rounding errors don't occlude outside of floater extents
- // floater_rect.stretch(-1);
- // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),
- // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
- // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
- // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
- // floater_3d_rect.translate(-0.5f, -0.5f);
- // glTranslatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
- // glScalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
- // gGL.color4fv(LLColor4::white.mV);
- // gGL.begin(LLVertexBuffer::QUADS);
- // {
- // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
- // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
- // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
- // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
- // }
- // gGL.end();
- // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- // }
- // glPopMatrix();
- //}
-
- LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
- LLPipeline::updateRenderDeferred();
-
- stop_glerror();
-
- if (to_texture)
- {
- gGL.setColorMask(true, true);
-
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.mDeferredScreen.bindTarget();
- glClearColor(0,0,0,0);
- gPipeline.mDeferredScreen.clear();
- }
- else
- {
- gPipeline.mScreen.bindTarget();
- gPipeline.mScreen.clear();
- }
-
- gGL.setColorMask(true, false);
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom");
-
- if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
- && !gRestoreGL)
- {
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
- gGL.setColorMask(true, false);
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
- }
- else
- {
- gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
- }
-
- gGL.setColorMask(true, true);
-
- //store this frame's modelview matrix for use
- //when rendering next frame's occlusion queries
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = gGLModelView[i];
- gGLLastProjection[i] = gGLProjection[i];
- }
- stop_glerror();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
-
- if (to_texture)
- {
- LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH);
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.mDeferredScreen.flush();
- if(LLRenderTarget::sUseFBO)
- {
- LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),
- gPipeline.mDeferredScreen.getHeight(), 0, 0,
- gPipeline.mDeferredScreen.getWidth(),
- gPipeline.mDeferredScreen.getHeight(),
- GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
- }
- else
- {
- gPipeline.mScreen.flush();
- if(LLRenderTarget::sUseFBO)
- {
- LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),
- gPipeline.mScreen.getHeight(), 0, 0,
- gPipeline.mScreen.getWidth(),
- gPipeline.mScreen.getHeight(),
- GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
- }
- }
-
- if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
- {
- gPipeline.renderDeferredLighting();
- }
-
- LLPipeline::sUnderWaterRender = FALSE;
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
- if (!for_snapshot)
- {
- LLFastTimer t(FTM_RENDER_UI);
- render_ui();
- }
-
-
- LLSpatialGroup::sNoDelete = FALSE;
- gPipeline.clearReferences();
-
- gPipeline.rebuildGroups();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
-
- stop_glerror();
-
- if (LLPipeline::sRenderFrameTest)
- {
- send_agent_resume();
- LLPipeline::sRenderFrameTest = FALSE;
- }
-
- display_stats();
-
- LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
-}
-
-void render_hud_attachments()
-{
- LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-
- glh::matrix4f current_proj = glh_get_current_projection();
- glh::matrix4f current_mod = glh_get_current_modelview();
-
- // clamp target zoom level to reasonable values
- gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
- // smoothly interpolate current zoom level
- gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
-
- if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
- {
- LLCamera hud_cam = *LLViewerCamera::getInstance();
- LLVector3 origin = hud_cam.getOrigin();
- hud_cam.setOrigin(-1.f,0,0);
- hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
- LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
-
- bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
-
- //only render hud objects
- gPipeline.pushRenderTypeMask();
-
- // turn off everything
- gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
- // turn on HUD
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- // turn on HUD particles
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
-
- // if particles are off, turn off hud-particles as well
- if (!render_particles)
- {
- // turn back off HUD particles
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
- }
-
- bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- if (has_ui)
- {
- gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- S32 use_occlusion = LLPipeline::sUseOcclusion;
- LLPipeline::sUseOcclusion = 0;
- LLPipeline::sDisableShaders = TRUE;
-
- //cull, sort, and render hud objects
- static LLCullResult result;
- LLSpatialGroup::sNoDelete = TRUE;
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- gPipeline.updateCull(hud_cam, result);
-
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
-
- gPipeline.stateSort(hud_cam, result);
-
- gPipeline.renderGeom(hud_cam);
-
- LLSpatialGroup::sNoDelete = FALSE;
- //gPipeline.clearReferences();
-
- render_hud_elements();
-
- //restore type mask
- gPipeline.popRenderTypeMask();
-
- if (has_ui)
- {
- gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
- LLPipeline::sUseOcclusion = use_occlusion;
- LLPipeline::sDisableShaders = FALSE;
- }
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- glh_set_current_projection(current_proj);
- glh_set_current_modelview(current_mod);
-}
-
-LLRect get_whole_screen_region()
-{
- LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
-
- // apply camera zoom transform (for high res screenshots)
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
- if (zoom_factor > 1.f)
- {
- S32 num_horizontal_tiles = llceil(zoom_factor);
- S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
- S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
- int tile_y = sub_region / num_horizontal_tiles;
- int tile_x = sub_region - (tile_y * num_horizontal_tiles);
-
- whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
- }
- return whole_screen;
-}
-
-bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
-{
- if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
- {
- F32 zoom_level = gAgentCamera.mHUDCurZoom;
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
- proj.element(2,2) = -0.01f;
-
- F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
-
- glh::matrix4f mat;
- F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
- F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
- mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
- mat.set_translate(
- glh::vec3f(clamp_rescale((F32)screen_region.getCenterX(), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
- clamp_rescale((F32)screen_region.getCenterY(), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
- 0.f));
- proj *= mat;
-
- glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
-
- mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
- mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
-
- tmp_model *= mat;
- model = tmp_model;
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
-{
- LLRect whole_screen = get_whole_screen_region();
- return get_hud_matrices(whole_screen, proj, model);
-}
-
-BOOL setup_hud_matrices()
-{
- LLRect whole_screen = get_whole_screen_region();
- return setup_hud_matrices(whole_screen);
-}
-
-BOOL setup_hud_matrices(const LLRect& screen_region)
-{
- glh::matrix4f proj, model;
- bool result = get_hud_matrices(screen_region, proj, model);
- if (!result) return result;
-
- // set up transform to keep HUD objects in front of camera
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(proj.m);
- glh_set_current_projection(proj);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(model.m);
- glh_set_current_modelview(model);
- return TRUE;
-}
-
-static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
-
-void render_ui(F32 zoom_factor, int subfield)
-{
- LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
- LLGLState::checkStates();
-
- glh::matrix4f saved_view = glh_get_current_modelview();
-
- if (!gSnapshot)
- {
- glPushMatrix();
- glLoadMatrixd(gGLLastModelView);
- glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
- }
-
- {
- BOOL to_texture = gPipeline.canUseVertexShaders() &&
- LLPipeline::sRenderGlow;
-
- if (to_texture)
- {
- gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
- }
-
- render_hud_elements();
- render_hud_attachments();
- }
-
- LLGLSDefault gls_default;
- LLGLSUIDefault gls_ui;
- {
- gPipeline.disableLights();
- }
-
- {
- gGL.color4f(1,1,1,1);
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLFastTimer t(FTM_RENDER_UI);
-
- if (!gDisconnected)
- {
- render_ui_3d();
- LLGLState::checkStates();
- }
- else
- {
- render_disconnected_background();
- }
-
- render_ui_2d();
- LLGLState::checkStates();
- }
- gGL.flush();
-
- {
- gViewerWindow->setup2DRender();
- gViewerWindow->updateDebugText();
- gViewerWindow->drawDebugText();
- }
-
- LLVertexBuffer::unbind();
- }
-
- if (!gSnapshot)
- {
- glh_set_current_modelview(saved_view);
- glPopMatrix();
- }
-
- if (gDisplaySwapBuffers)
- {
- LLFastTimer t(FTM_SWAP);
- gViewerWindow->mWindow->swapBuffers();
- }
- gDisplaySwapBuffers = TRUE;
-}
-
-void renderCoordinateAxes()
-{
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.begin(LLRender::LINES);
- gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(2.0f, 0.0f, 0.0f);
- gGL.vertex3f(3.0f, 0.0f, 0.0f);
- gGL.vertex3f(5.0f, 0.0f, 0.0f);
- gGL.vertex3f(6.0f, 0.0f, 0.0f);
- gGL.vertex3f(8.0f, 0.0f, 0.0f);
- // Make an X
- gGL.vertex3f(11.0f, 1.0f, 1.0f);
- gGL.vertex3f(11.0f, -1.0f, -1.0f);
- gGL.vertex3f(11.0f, 1.0f, -1.0f);
- gGL.vertex3f(11.0f, -1.0f, 1.0f);
-
- gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 2.0f, 0.0f);
- gGL.vertex3f(0.0f, 3.0f, 0.0f);
- gGL.vertex3f(0.0f, 5.0f, 0.0f);
- gGL.vertex3f(0.0f, 6.0f, 0.0f);
- gGL.vertex3f(0.0f, 8.0f, 0.0f);
- // Make a Y
- gGL.vertex3f(1.0f, 11.0f, 1.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(-1.0f, 11.0f, 1.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(0.0f, 11.0f, 0.0f);
- gGL.vertex3f(0.0f, 11.0f, -1.0f);
-
- gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 0.0f, 2.0f);
- gGL.vertex3f(0.0f, 0.0f, 3.0f);
- gGL.vertex3f(0.0f, 0.0f, 5.0f);
- gGL.vertex3f(0.0f, 0.0f, 6.0f);
- gGL.vertex3f(0.0f, 0.0f, 8.0f);
- // Make a Z
- gGL.vertex3f(-1.0f, 1.0f, 11.0f);
- gGL.vertex3f(1.0f, 1.0f, 11.0f);
- gGL.vertex3f(1.0f, 1.0f, 11.0f);
- gGL.vertex3f(-1.0f, -1.0f, 11.0f);
- gGL.vertex3f(-1.0f, -1.0f, 11.0f);
- gGL.vertex3f(1.0f, -1.0f, 11.0f);
- gGL.end();
-}
-
-
-void draw_axes()
-{
- LLGLSUIDefault gls_ui;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- // A vertical white line at origin
- LLVector3 v = gAgent.getPositionAgent();
- gGL.begin(LLRender::LINES);
- gGL.color3f(1.0f, 1.0f, 1.0f);
- gGL.vertex3f(0.0f, 0.0f, 0.0f);
- gGL.vertex3f(0.0f, 0.0f, 40.0f);
- gGL.end();
- // Some coordinate axes
- glPushMatrix();
- glTranslatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
- renderCoordinateAxes();
- glPopMatrix();
-}
-
-void render_ui_3d()
-{
- LLGLSPipeline gls_pipeline;
-
- //////////////////////////////////////
- //
- // Render 3D UI elements
- // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
- // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
- //
-
- /////////////////////////////////////////////////////////////
- //
- // Render 2.5D elements (2D elements in the world)
- // Stuff without z writes
- //
-
- // Debugging stuff goes before the UI.
-
- // Coordinate axes
- if (gSavedSettings.getBOOL("ShowAxes"))
- {
- draw_axes();
- }
-
- stop_glerror();
-
- gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements
- stop_glerror();
-}
-
-void render_ui_2d()
-{
- LLGLSUIDefault gls_ui;
-
- /////////////////////////////////////////////////////////////
- //
- // Render 2D UI elements that overlay the world (no z compare)
-
- // Disable wireframe mode below here, as this is HUD/menus
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- // Menu overlays, HUD, etc
- gViewerWindow->setup2DRender();
-
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
-
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
- LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
- }
-
- stop_glerror();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- // render outline for HUD
- if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
- {
- gGL.pushMatrix();
- S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
- S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
- glScalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
- glTranslatef((F32)half_width, (F32)half_height, 0.f);
- F32 zoom = gAgentCamera.mHUDCurZoom;
- glScalef(zoom,zoom,1.f);
- gGL.color4fv(LLColor4::white.mV);
- gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
- gGL.popMatrix();
- stop_glerror();
- }
-
-
- if (gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- if (LLUI::sDirty)
- {
- LLUI::sDirty = FALSE;
- LLRect t_rect;
-
- gPipeline.mUIScreen.bindTarget();
- gGL.setColorMask(true, true);
- {
- static const S32 pad = 8;
-
- LLUI::sDirtyRect.mLeft -= pad;
- LLUI::sDirtyRect.mRight += pad;
- LLUI::sDirtyRect.mBottom -= pad;
- LLUI::sDirtyRect.mTop += pad;
-
- LLGLEnable scissor(GL_SCISSOR_TEST);
- static LLRect last_rect = LLUI::sDirtyRect;
-
- //union with last rect to avoid mouse poop
- last_rect.unionWith(LLUI::sDirtyRect);
-
- t_rect = LLUI::sDirtyRect;
- LLUI::sDirtyRect = last_rect;
- last_rect = t_rect;
-
- last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
- last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
- last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
- last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
-
- LLRect clip_rect(last_rect);
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- gViewerWindow->draw();
- }
-
- gPipeline.mUIScreen.flush();
- gGL.setColorMask(true, false);
-
- LLUI::sDirtyRect = t_rect;
- }
-
- LLGLDisable cull(GL_CULL_FACE);
- LLGLDisable blend(GL_BLEND);
- S32 width = gViewerWindow->getWindowWidthScaled();
- S32 height = gViewerWindow->getWindowHeightScaled();
- gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.color4f(1,1,1,1);
- gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0);
- gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0);
- gGL.texCoord2f(0, height); gGL.vertex2i(0, height);
- gGL.texCoord2f(width, height); gGL.vertex2i(width, height);
- gGL.end();
- }
- else
- {
- gViewerWindow->draw();
- }
-
-
-
- // reset current origin for font rendering, in case of tiling render
- LLFontGL::sCurOrigin.set(0, 0);
-}
-
-void render_disconnected_background()
-{
- gGL.color4f(1,1,1,1);
- if (!gDisconnectedImagep && gDisconnected)
- {
- llinfos << "Loading last bitmap..." << llendl;
-
- std::string temp_str;
- temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME;
-
- LLPointer<LLImageBMP> image_bmp = new LLImageBMP;
- if( !image_bmp->load(temp_str) )
- {
- //llinfos << "Bitmap load failed" << llendl;
- return;
- }
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- if (!image_bmp->decode(raw, 0.0f))
- {
- llinfos << "Bitmap decode failed" << llendl;
- gDisconnectedImagep = NULL;
- return;
- }
-
- U8 *rawp = raw->getData();
- S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight();
- for (S32 i = 0; i < npixels; i++)
- {
- S32 sum = 0;
- sum = *rawp + *(rawp+1) + *(rawp+2);
- sum /= 3;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- *rawp = ((S32)sum*6 + *rawp)/7;
- rawp++;
- }
-
-
- raw->expandToPowerOfTwo();
- gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE );
- gStartTexture = gDisconnectedImagep;
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- // Make sure the progress view always fills the entire window.
- S32 width = gViewerWindow->getWindowWidthScaled();
- S32 height = gViewerWindow->getWindowHeightScaled();
-
- if (gDisconnectedImagep)
- {
- LLGLSUIDefault gls_ui;
- gViewerWindow->setup2DRender();
- glPushMatrix();
- {
- // scale ui to reflect UIScaleFactor
- // this can't be done in setup2DRender because it requires a
- // pushMatrix/popMatrix pair
- const LLVector2& display_scale = gViewerWindow->getDisplayScale();
- glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
-
- gGL.getTexUnit(0)->bind(gDisconnectedImagep);
- gGL.color4f(1.f, 1.f, 1.f, 1.f);
- gl_rect_2d_simple_tex(width, height);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
- glPopMatrix();
- }
- gGL.flush();
-}
-
-void display_cleanup()
-{
- gDisconnectedImagep = NULL;
-}
+/**
+ * @file llviewerdisplay.cpp
+ * @brief LLViewerDisplay class implementation
+ *
+ * $LicenseInfo:firstyear=2004&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerdisplay.h"
+
+#include "llgl.h"
+#include "llrender.h"
+#include "llglheaders.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llviewercontrol.h"
+#include "llcoord.h"
+#include "llcriticaldamp.h"
+#include "lldir.h"
+#include "lldynamictexture.h"
+#include "lldrawpoolalpha.h"
+#include "llfeaturemanager.h"
+//#include "llfirstuse.h"
+#include "llhudmanager.h"
+#include "llimagebmp.h"
+#include "llmemory.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "llstartup.h"
+#include "lltoolfocus.h"
+#include "lltoolmgr.h"
+#include "lltooldraganddrop.h"
+#include "lltoolpie.h"
+#include "lltracker.h"
+#include "lltrans.h"
+#include "llui.h"
+#include "llviewercamera.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerwindow.h"
+#include "llvoavatarself.h"
+#include "llvograss.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "llspatialpartition.h"
+#include "llappviewer.h"
+#include "llstartup.h"
+#include "llviewershadermgr.h"
+#include "llfasttimer.h"
+#include "llfloatertools.h"
+#include "llviewertexturelist.h"
+#include "llfocusmgr.h"
+#include "llcubemap.h"
+#include "llviewerregion.h"
+#include "lldrawpoolwater.h"
+#include "lldrawpoolbump.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llpostprocess.h"
+
+extern LLPointer<LLViewerTexture> gStartTexture;
+
+LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
+
+// used to toggle renderer back on after teleport
+const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain
+const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
+const F32 TELEPORT_LOCAL_DELAY = 1.0f; // Delay to prevent teleports after starting an in-sim teleport.
+BOOL gTeleportDisplay = FALSE;
+LLFrameTimer gTeleportDisplayTimer;
+LLFrameTimer gTeleportArrivalTimer;
+const F32 RESTORE_GL_TIME = 5.f; // Wait this long while reloading textures before we raise the curtain
+
+BOOL gForceRenderLandFence = FALSE;
+BOOL gDisplaySwapBuffers = FALSE;
+BOOL gDepthDirty = FALSE;
+BOOL gResizeScreenTexture = FALSE;
+BOOL gWindowResized = FALSE;
+BOOL gSnapshot = FALSE;
+
+U32 gRecentFrameCount = 0; // number of 'recent' frames
+LLFrameTimer gRecentFPSTime;
+LLFrameTimer gRecentMemoryTime;
+
+// Rendering stuff
+void pre_show_depth_buffer();
+void post_show_depth_buffer();
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+void render_hud_attachments();
+void render_ui_3d();
+void render_ui_2d();
+void render_disconnected_background();
+
+void display_startup()
+{
+ if ( !gViewerWindow->getActive()
+ || !gViewerWindow->mWindow->getVisible()
+ || gViewerWindow->mWindow->getMinimized() )
+ {
+ return;
+ }
+
+ gPipeline.updateGL();
+
+ // Update images?
+ //gImageList.updateImages(0.01f);
+
+ LLGLSDefault gls_default;
+
+ // Required for HTML update in login screen
+ static S32 frame_count = 0;
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ if (frame_count++ > 1) // make sure we have rendered a frame first
+ {
+ LLViewerDynamicTexture::updateAllInstances();
+ }
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ LLGLSUIDefault gls_ui;
+ gPipeline.disableLights();
+
+ gViewerWindow->setup2DRender();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ gGL.color4f(1,1,1,1);
+ gViewerWindow->draw();
+ gGL.flush();
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ gViewerWindow->mWindow->swapBuffers();
+ glClear(GL_DEPTH_BUFFER_BIT);
+}
+
+void display_update_camera()
+{
+ LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
+ // TODO: cut draw distance down if customizing avatar?
+ // TODO: cut draw distance on per-parcel basis?
+
+ // Cut draw distance in half when customizing avatar,
+ // but on the viewer only.
+ F32 final_far = gAgentCamera.mDrawDistance;
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
+ {
+ final_far *= 0.5f;
+ }
+ LLViewerCamera::getInstance()->setFar(final_far);
+ gViewerWindow->setup3DRender();
+
+ // update all the sky/atmospheric/water settings
+ LLWLParamManager::instance()->update(LLViewerCamera::getInstance());
+ LLWaterParamManager::instance()->update(LLViewerCamera::getInstance());
+
+ // Update land visibility too
+ LLWorld::getInstance()->setLandFarClip(final_far);
+}
+
+// Write some stats to llinfos
+void display_stats()
+{
+ F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
+ if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
+ {
+ F32 fps = gRecentFrameCount / fps_log_freq;
+ llinfos << llformat("FPS: %.02f", fps) << llendl;
+ gRecentFrameCount = 0;
+ gRecentFPSTime.reset();
+ }
+ F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
+ if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
+ {
+ gMemoryAllocated = LLMemory::getCurrentRSS();
+ U32 memory = (U32)(gMemoryAllocated / (1024*1024));
+ llinfos << llformat("MEMORY: %d MB", memory) << llendl;
+ gRecentMemoryTime.reset();
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_PICK("Picking");
+static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
+static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
+static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
+
+// Paint the display!
+void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
+{
+ LLMemType mt_render(LLMemType::MTYPE_RENDER);
+ LLFastTimer t(FTM_RENDER);
+
+ if (gWindowResized)
+ { //skip render on frames where window has been resized
+ gGL.flush();
+ glClear(GL_COLOR_BUFFER_BIT);
+ gViewerWindow->mWindow->swapBuffers();
+ gPipeline.resizeScreenTexture();
+ gResizeScreenTexture = FALSE;
+ gWindowResized = FALSE;
+ return;
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ { //hack to make sky show up in deferred snapshots
+ for_snapshot = FALSE;
+ }
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ send_agent_pause();
+ }
+
+ gSnapshot = for_snapshot;
+
+ LLGLSDefault gls_default;
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ stop_glerror();
+
+ gPipeline.disableLights();
+
+ stop_glerror();
+
+ // Don't draw if the window is hidden or minimized.
+ // In fact, must explicitly check the minimized state before drawing.
+ // Attempting to draw into a minimized window causes a GL error. JC
+ if ( !gViewerWindow->getActive()
+ || !gViewerWindow->mWindow->getVisible()
+ || gViewerWindow->mWindow->getMinimized() )
+ {
+ // Clean up memory the pools may have allocated
+ if (rebuild)
+ {
+ stop_glerror();
+ gPipeline.rebuildPools();
+ stop_glerror();
+ }
+
+ stop_glerror();
+ gViewerWindow->returnEmptyPicks();
+ stop_glerror();
+ return;
+ }
+
+ gViewerWindow->checkSettings();
+
+ {
+ LLFastTimer ftm(FTM_PICK);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Pick");
+ gViewerWindow->performPick();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ //////////////////////////////////////////////////////////
+ //
+ // Logic for forcing window updates if we're in drone mode.
+ //
+
+ // *TODO: Investigate running display() during gHeadlessClient. See if this early exit is needed DK 2011-02-18
+ if (gHeadlessClient)
+ {
+#if LL_WINDOWS
+ static F32 last_update_time = 0.f;
+ if ((gFrameTimeSeconds - last_update_time) > 1.f)
+ {
+ InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE);
+ last_update_time = gFrameTimeSeconds;
+ }
+#elif LL_DARWIN
+ // MBW -- Do something clever here.
+#endif
+ // Not actually rendering, don't bother.
+ return;
+ }
+
+
+ //
+ // Bail out if we're in the startup state and don't want to try to
+ // render the world.
+ //
+ if (LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
+ display_startup();
+ return;
+ }
+
+ //LLGLState::verify(FALSE);
+
+ /////////////////////////////////////////////////
+ //
+ // Update GL Texture statistics (used for discard logic?)
+ //
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
+ stop_glerror();
+
+ LLImageGL::updateStats(gFrameTimeSeconds);
+
+ LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
+ LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
+
+ gPipeline.mBackfaceCull = TRUE;
+ gFrameCount++;
+ gRecentFrameCount++;
+ if (gFocusMgr.getAppHasFocus())
+ {
+ gForegroundFrameCount++;
+ }
+
+ //////////////////////////////////////////////////////////
+ //
+ // Display start screen if we're teleporting, and skip render
+ //
+
+ if (gTeleportDisplay)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
+ const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
+
+ S32 attach_count = 0;
+ if (isAgentAvatarValid())
+ {
+ attach_count = gAgentAvatarp->getAttachmentCount();
+ }
+ F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
+ F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
+ F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
+ if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) )
+ {
+ // Give up. Don't keep the UI locked forever.
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ gAgent.setTeleportMessage(std::string());
+ }
+
+ const std::string& message = gAgent.getTeleportMessage();
+ switch( gAgent.getTeleportState() )
+ {
+ case LLAgent::TELEPORT_START:
+ // Transition to REQUESTED. Viewer has sent some kind
+ // of TeleportRequest to the source simulator
+ gTeleportDisplayTimer.reset();
+ gViewerWindow->setShowProgress(TRUE);
+ gViewerWindow->setProgressPercent(0);
+ gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED );
+ gAgent.setTeleportMessage(
+ LLAgent::sTeleportProgressMessages["requesting"]);
+ break;
+
+ case LLAgent::TELEPORT_REQUESTED:
+ // Waiting for source simulator to respond
+ gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) );
+ gViewerWindow->setProgressString(message);
+ break;
+
+ case LLAgent::TELEPORT_MOVING:
+ // Viewer has received destination location from source simulator
+ gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) );
+ gViewerWindow->setProgressString(message);
+ break;
+
+ case LLAgent::TELEPORT_START_ARRIVAL:
+ // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator
+ gTeleportArrivalTimer.reset();
+ gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
+ gViewerWindow->setProgressPercent(75.f);
+ gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING );
+ gAgent.setTeleportMessage(
+ LLAgent::sTeleportProgressMessages["arriving"]);
+ gTextureList.mForceResetTextureStats = TRUE;
+ gAgentCamera.resetView(TRUE, TRUE);
+ break;
+
+ case LLAgent::TELEPORT_ARRIVING:
+ // Make the user wait while content "pre-caches"
+ {
+ F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY);
+ if( arrival_fraction > 1.f )
+ {
+ arrival_fraction = 1.f;
+ //LLFirstUse::useTeleport();
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
+ gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f);
+ gViewerWindow->setProgressString(message);
+ }
+ break;
+
+ case LLAgent::TELEPORT_LOCAL:
+ // Short delay when teleporting in the same sim (progress screen active but not shown - did not
+ // fall-through from TELEPORT_START)
+ {
+ if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY )
+ {
+ //LLFirstUse::useTeleport();
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ }
+ break;
+
+ case LLAgent::TELEPORT_NONE:
+ // No teleport in progress
+ gViewerWindow->setShowProgress(FALSE);
+ gTeleportDisplay = FALSE;
+ break;
+ }
+ }
+ else if(LLAppViewer::instance()->logoutRequestSent())
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
+ F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
+ if (percent_done > 100.f)
+ {
+ percent_done = 100.f;
+ }
+
+ if( LLApp::isExiting() )
+ {
+ percent_done = 100.f;
+ }
+
+ gViewerWindow->setProgressPercent( percent_done );
+ }
+ else
+ if (gRestoreGL)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
+ F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
+ if( percent_done > 100.f )
+ {
+ gViewerWindow->setShowProgress(FALSE);
+ gRestoreGL = FALSE;
+ }
+ else
+ {
+
+ if( LLApp::isExiting() )
+ {
+ percent_done = 100.f;
+ }
+
+ gViewerWindow->setProgressPercent( percent_done );
+ }
+ }
+
+ //////////////////////////
+ //
+ // Prepare for the next frame
+ //
+
+ /////////////////////////////
+ //
+ // Update the camera
+ //
+ //
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
+ LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
+ LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+
+ //////////////////////////
+ //
+ // clear the next buffer
+ // (must follow dynamic texture writing since that uses the frame buffer)
+ //
+
+ if (gDisconnected)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
+ render_ui();
+ }
+
+ //////////////////////////
+ //
+ // Set rendering options
+ //
+ //
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
+ stop_glerror();
+
+ ///////////////////////////////////////
+ //
+ // Slam lighting parameters back to our defaults.
+ // Note that these are not the same as GL defaults...
+
+ stop_glerror();
+ F32 one[4] = {1.f, 1.f, 1.f, 1.f};
+ glLightModelfv (GL_LIGHT_MODEL_AMBIENT,one);
+ stop_glerror();
+
+ /////////////////////////////////////
+ //
+ // Render
+ //
+ // Actually push all of our triangles to the screen.
+ //
+
+ // do render-to-texture stuff here
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
+ LLFastTimer t(FTM_UPDATE_TEXTURES);
+ if (LLViewerDynamicTexture::updateAllInstances())
+ {
+ gGL.setColorMask(true, true);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ }
+
+ gViewerWindow->setup3DViewport();
+
+ gPipeline.resetFrameStats(); // Reset per-frame statistics.
+
+ if (!gDisconnected)
+ {
+ LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ { //don't draw hud objects in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
+ { //don't draw hud particles in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ }
+
+ //upkeep gl name pools
+ LLGLNamePool::upkeepPools();
+
+ stop_glerror();
+ display_update_camera();
+ stop_glerror();
+
+ // *TODO: merge these two methods
+ {
+ LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
+ LLHUDManager::getInstance()->updateEffects();
+ LLHUDObject::updateAll();
+ stop_glerror();
+ }
+
+ {
+ LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
+ const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
+ gPipeline.createObjects(max_geom_update_time);
+ gPipeline.updateGeom(max_geom_update_time);
+ stop_glerror();
+ }
+
+ gPipeline.updateGL();
+ stop_glerror();
+
+ S32 water_clip = 0;
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
+ (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||
+ gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
+ {
+ if (LLViewerCamera::getInstance()->cameraUnderWater())
+ {
+ water_clip = -1;
+ }
+ else
+ {
+ water_clip = 1;
+ }
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
+
+ //Increment drawable frame counter
+ LLDrawable::incrementVisible();
+
+ LLSpatialGroup::sNoDelete = TRUE;
+ LLPipeline::sUseOcclusion =
+ (!gUseWireframe
+ && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")
+ && gSavedSettings.getBOOL("UseOcclusion")
+ && gGLManager.mHasOcclusionQuery) ? 2 : 0;
+
+ /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
+ { //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
+ LLPipeline::sUseOcclusion = 3;
+ }*/
+
+ LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred");
+ LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred");
+ LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
+ LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
+ LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
+
+ S32 occlusion = LLPipeline::sUseOcclusion;
+ if (gDepthDirty)
+ { //depth buffer is invalid, don't overwrite occlusion state
+ LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+ }
+ gDepthDirty = FALSE;
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ static LLCullResult result;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
+ stop_glerror();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ BOOL to_texture = gPipeline.canUseVertexShaders() &&
+ LLPipeline::sRenderGlow;
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
+
+ {
+ LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP);
+ {
+ LLFastTimer ftm(FTM_CLIENT_COPY);
+ LLVertexBuffer::clientCopy(0.016);
+ }
+
+ if (gResizeScreenTexture)
+ {
+ gResizeScreenTexture = FALSE;
+ gPipeline.resizeScreenTexture();
+ }
+
+ gGL.setColorMask(true, true);
+ glClearColor(0,0,0,0);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ if (!for_snapshot)
+ {
+ if (gFrameCount > 1)
+ { //for some reason, ATI 4800 series will error out if you
+ //try to generate a shadow before the first frame is through
+ gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ glh::matrix4f proj = glh_get_current_projection();
+ glh::matrix4f mod = glh_get_current_modelview();
+ glViewport(0,0,512,512);
+ LLVOAvatar::updateFreezeCounter() ;
+ LLVOAvatar::updateImpostors();
+
+ glh_set_current_projection(proj);
+ glh_set_current_modelview(mod);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(proj.m);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(mod.m);
+ gViewerWindow->setup3DViewport();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ }
+ glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ }
+
+ //if (!for_snapshot)
+ {
+ LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
+ gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
+ gPipeline.generateHighlight(*LLViewerCamera::getInstance());
+ }
+
+ //////////////////////////////////////
+ //
+ // Update images, using the image stats generated during object update/culling
+ //
+ // Can put objects onto the retextured list.
+ //
+ // Doing this here gives hardware occlusion queries extra time to complete
+ LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
+
+ {
+ LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
+ LLFastTimer t(FTM_IMAGE_UPDATE);
+
+ LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(),
+ LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean());
+
+ gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
+
+ F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
+ max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
+ gTextureList.updateImages(max_image_decode_time);
+
+ //remove dead textures from GL
+ LLImageGL::deleteDeadTextures();
+ stop_glerror();
+ }
+ ///////////////////////////////////
+ //
+ // StateSort
+ //
+ // Responsible for taking visible objects, and adding them to the appropriate draw orders.
+ // In the case of alpha objects, z-sorts them first.
+ // Also creates special lists for outlines and selected face rendering.
+ //
+ LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
+ {
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
+ gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
+ stop_glerror();
+
+ if (rebuild)
+ {
+ //////////////////////////////////////
+ //
+ // rebuildPools
+ //
+ //
+ gPipeline.rebuildPools();
+ stop_glerror();
+ }
+ }
+
+ LLPipeline::sUseOcclusion = occlusion;
+
+ {
+ LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY);
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
+ LLFastTimer t(FTM_UPDATE_SKY);
+ gSky.updateSky();
+ }
+
+ if(gUseWireframe)
+ {
+ glClearColor(0.5f, 0.5f, 0.5f, 0.f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
+
+ //// render frontmost floater opaque for occlusion culling purposes
+ //LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
+ //// assumes frontmost floater with focus is opaque
+ //if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
+ //{
+ // glMatrixMode(GL_MODELVIEW);
+ // glPushMatrix();
+ // {
+ // gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+ // glLoadIdentity();
+
+ // LLRect floater_rect = frontmost_floaterp->calcScreenRect();
+ // // deflate by one pixel so rounding errors don't occlude outside of floater extents
+ // floater_rect.stretch(-1);
+ // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),
+ // (F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
+ // (F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
+ // (F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
+ // floater_3d_rect.translate(-0.5f, -0.5f);
+ // glTranslatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
+ // glScalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
+ // gGL.color4fv(LLColor4::white.mV);
+ // gGL.begin(LLVertexBuffer::QUADS);
+ // {
+ // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
+ // gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
+ // }
+ // gGL.end();
+ // glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ // }
+ // glPopMatrix();
+ //}
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
+ LLPipeline::updateRenderDeferred();
+
+ stop_glerror();
+
+ if (to_texture)
+ {
+ gGL.setColorMask(true, true);
+
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.mDeferredScreen.bindTarget();
+ glClearColor(0,0,0,0);
+ gPipeline.mDeferredScreen.clear();
+ }
+ else
+ {
+ gPipeline.mScreen.bindTarget();
+ gPipeline.mScreen.clear();
+ }
+
+ gGL.setColorMask(true, false);
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom");
+
+ if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
+ && !gRestoreGL)
+ {
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
+ gGL.setColorMask(true, false);
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
+ }
+ else
+ {
+ gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
+ }
+
+ gGL.setColorMask(true, true);
+
+ //store this frame's modelview matrix for use
+ //when rendering next frame's occlusion queries
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = gGLModelView[i];
+ gGLLastProjection[i] = gGLProjection[i];
+ }
+ stop_glerror();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");
+
+ if (to_texture)
+ {
+ LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH);
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.mDeferredScreen.flush();
+ if(LLRenderTarget::sUseFBO)
+ {
+ LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),
+ gPipeline.mDeferredScreen.getHeight(), 0, 0,
+ gPipeline.mDeferredScreen.getWidth(),
+ gPipeline.mDeferredScreen.getHeight(),
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+ else
+ {
+ gPipeline.mScreen.flush();
+ if(LLRenderTarget::sUseFBO)
+ {
+ LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),
+ gPipeline.mScreen.getHeight(), 0, 0,
+ gPipeline.mScreen.getWidth(),
+ gPipeline.mScreen.getHeight(),
+ GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+ }
+
+ if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+ {
+ gPipeline.renderDeferredLighting();
+ }
+
+ LLPipeline::sUnderWaterRender = FALSE;
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
+ if (!for_snapshot)
+ {
+ LLFastTimer t(FTM_RENDER_UI);
+ render_ui();
+ }
+
+
+ LLSpatialGroup::sNoDelete = FALSE;
+ gPipeline.clearReferences();
+
+ gPipeline.rebuildGroups();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
+
+ stop_glerror();
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ send_agent_resume();
+ LLPipeline::sRenderFrameTest = FALSE;
+ }
+
+ display_stats();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
+}
+
+void render_hud_attachments()
+{
+ LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glh::matrix4f current_proj = glh_get_current_projection();
+ glh::matrix4f current_mod = glh_get_current_modelview();
+
+ // clamp target zoom level to reasonable values
+ gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+ // smoothly interpolate current zoom level
+ gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
+
+ if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
+ {
+ LLCamera hud_cam = *LLViewerCamera::getInstance();
+ LLVector3 origin = hud_cam.getOrigin();
+ hud_cam.setOrigin(-1.f,0,0);
+ hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
+ LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
+
+ bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
+
+ //only render hud objects
+ gPipeline.pushRenderTypeMask();
+
+ // turn off everything
+ gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
+ // turn on HUD
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ // turn on HUD particles
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+
+ // if particles are off, turn off hud-particles as well
+ if (!render_particles)
+ {
+ // turn back off HUD particles
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ }
+
+ bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ if (has_ui)
+ {
+ gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ S32 use_occlusion = LLPipeline::sUseOcclusion;
+ LLPipeline::sUseOcclusion = 0;
+ LLPipeline::sDisableShaders = TRUE;
+
+ //cull, sort, and render hud objects
+ static LLCullResult result;
+ LLSpatialGroup::sNoDelete = TRUE;
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ gPipeline.updateCull(hud_cam, result);
+
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
+
+ gPipeline.stateSort(hud_cam, result);
+
+ gPipeline.renderGeom(hud_cam);
+
+ LLSpatialGroup::sNoDelete = FALSE;
+ //gPipeline.clearReferences();
+
+ render_hud_elements();
+
+ //restore type mask
+ gPipeline.popRenderTypeMask();
+
+ if (has_ui)
+ {
+ gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+ LLPipeline::sUseOcclusion = use_occlusion;
+ LLPipeline::sDisableShaders = FALSE;
+ }
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glh_set_current_projection(current_proj);
+ glh_set_current_modelview(current_mod);
+}
+
+LLRect get_whole_screen_region()
+{
+ LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
+
+ // apply camera zoom transform (for high res screenshots)
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+ if (zoom_factor > 1.f)
+ {
+ S32 num_horizontal_tiles = llceil(zoom_factor);
+ S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
+ S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
+ int tile_y = sub_region / num_horizontal_tiles;
+ int tile_x = sub_region - (tile_y * num_horizontal_tiles);
+
+ whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
+ }
+ return whole_screen;
+}
+
+bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
+{
+ if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
+ {
+ F32 zoom_level = gAgentCamera.mHUDCurZoom;
+ LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
+
+ F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
+ proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
+ proj.element(2,2) = -0.01f;
+
+ F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
+
+ glh::matrix4f mat;
+ F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
+ F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
+ mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
+ mat.set_translate(
+ glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
+ clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
+ 0.f));
+ proj *= mat;
+
+ glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
+
+ mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
+ mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
+
+ tmp_model *= mat;
+ model = tmp_model;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
+{
+ LLRect whole_screen = get_whole_screen_region();
+ return get_hud_matrices(whole_screen, proj, model);
+}
+
+BOOL setup_hud_matrices()
+{
+ LLRect whole_screen = get_whole_screen_region();
+ return setup_hud_matrices(whole_screen);
+}
+
+BOOL setup_hud_matrices(const LLRect& screen_region)
+{
+ glh::matrix4f proj, model;
+ bool result = get_hud_matrices(screen_region, proj, model);
+ if (!result) return result;
+
+ // set up transform to keep HUD objects in front of camera
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(proj.m);
+ glh_set_current_projection(proj);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(model.m);
+ glh_set_current_modelview(model);
+ return TRUE;
+}
+
+static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
+
+void render_ui(F32 zoom_factor, int subfield)
+{
+ LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
+ LLGLState::checkStates();
+
+ glh::matrix4f saved_view = glh_get_current_modelview();
+
+ if (!gSnapshot)
+ {
+ glPushMatrix();
+ glLoadMatrixd(gGLLastModelView);
+ glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
+ }
+
+ {
+ BOOL to_texture = gPipeline.canUseVertexShaders() &&
+ LLPipeline::sRenderGlow;
+
+ if (to_texture)
+ {
+ gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
+ }
+
+ render_hud_elements();
+ render_hud_attachments();
+ }
+
+ LLGLSDefault gls_default;
+ LLGLSUIDefault gls_ui;
+ {
+ gPipeline.disableLights();
+ }
+
+ {
+ gGL.color4f(1,1,1,1);
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLFastTimer t(FTM_RENDER_UI);
+
+ if (!gDisconnected)
+ {
+ render_ui_3d();
+ LLGLState::checkStates();
+ }
+ else
+ {
+ render_disconnected_background();
+ }
+
+ render_ui_2d();
+ LLGLState::checkStates();
+ }
+ gGL.flush();
+
+ {
+ gViewerWindow->setup2DRender();
+ gViewerWindow->updateDebugText();
+ gViewerWindow->drawDebugText();
+ }
+
+ LLVertexBuffer::unbind();
+ }
+
+ if (!gSnapshot)
+ {
+ glh_set_current_modelview(saved_view);
+ glPopMatrix();
+ }
+
+ if (gDisplaySwapBuffers)
+ {
+ LLFastTimer t(FTM_SWAP);
+ gViewerWindow->mWindow->swapBuffers();
+ }
+ gDisplaySwapBuffers = TRUE;
+}
+
+void renderCoordinateAxes()
+{
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.begin(LLRender::LINES);
+ gGL.color3f(1.0f, 0.0f, 0.0f); // i direction = X-Axis = red
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(2.0f, 0.0f, 0.0f);
+ gGL.vertex3f(3.0f, 0.0f, 0.0f);
+ gGL.vertex3f(5.0f, 0.0f, 0.0f);
+ gGL.vertex3f(6.0f, 0.0f, 0.0f);
+ gGL.vertex3f(8.0f, 0.0f, 0.0f);
+ // Make an X
+ gGL.vertex3f(11.0f, 1.0f, 1.0f);
+ gGL.vertex3f(11.0f, -1.0f, -1.0f);
+ gGL.vertex3f(11.0f, 1.0f, -1.0f);
+ gGL.vertex3f(11.0f, -1.0f, 1.0f);
+
+ gGL.color3f(0.0f, 1.0f, 0.0f); // j direction = Y-Axis = green
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 2.0f, 0.0f);
+ gGL.vertex3f(0.0f, 3.0f, 0.0f);
+ gGL.vertex3f(0.0f, 5.0f, 0.0f);
+ gGL.vertex3f(0.0f, 6.0f, 0.0f);
+ gGL.vertex3f(0.0f, 8.0f, 0.0f);
+ // Make a Y
+ gGL.vertex3f(1.0f, 11.0f, 1.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(-1.0f, 11.0f, 1.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(0.0f, 11.0f, 0.0f);
+ gGL.vertex3f(0.0f, 11.0f, -1.0f);
+
+ gGL.color3f(0.0f, 0.0f, 1.0f); // Z-Axis = blue
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 2.0f);
+ gGL.vertex3f(0.0f, 0.0f, 3.0f);
+ gGL.vertex3f(0.0f, 0.0f, 5.0f);
+ gGL.vertex3f(0.0f, 0.0f, 6.0f);
+ gGL.vertex3f(0.0f, 0.0f, 8.0f);
+ // Make a Z
+ gGL.vertex3f(-1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(1.0f, 1.0f, 11.0f);
+ gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+ gGL.vertex3f(-1.0f, -1.0f, 11.0f);
+ gGL.vertex3f(1.0f, -1.0f, 11.0f);
+ gGL.end();
+}
+
+
+void draw_axes()
+{
+ LLGLSUIDefault gls_ui;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ // A vertical white line at origin
+ LLVector3 v = gAgent.getPositionAgent();
+ gGL.begin(LLRender::LINES);
+ gGL.color3f(1.0f, 1.0f, 1.0f);
+ gGL.vertex3f(0.0f, 0.0f, 0.0f);
+ gGL.vertex3f(0.0f, 0.0f, 40.0f);
+ gGL.end();
+ // Some coordinate axes
+ glPushMatrix();
+ glTranslatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
+ renderCoordinateAxes();
+ glPopMatrix();
+}
+
+void render_ui_3d()
+{
+ LLGLSPipeline gls_pipeline;
+
+ //////////////////////////////////////
+ //
+ // Render 3D UI elements
+ // NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
+ // so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
+ //
+
+ /////////////////////////////////////////////////////////////
+ //
+ // Render 2.5D elements (2D elements in the world)
+ // Stuff without z writes
+ //
+
+ // Debugging stuff goes before the UI.
+
+ // Coordinate axes
+ if (gSavedSettings.getBOOL("ShowAxes"))
+ {
+ draw_axes();
+ }
+
+ stop_glerror();
+
+ gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements
+ stop_glerror();
+}
+
+void render_ui_2d()
+{
+ LLGLSUIDefault gls_ui;
+
+ /////////////////////////////////////////////////////////////
+ //
+ // Render 2D UI elements that overlay the world (no z compare)
+
+ // Disable wireframe mode below here, as this is HUD/menus
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ // Menu overlays, HUD, etc
+ gViewerWindow->setup2DRender();
+
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+
+ if (zoom_factor > 1.f)
+ {
+ //decompose subregion number to x and y values
+ int pos_y = sub_region / llceil(zoom_factor);
+ int pos_x = sub_region - (pos_y*llceil(zoom_factor));
+ // offset for this tile
+ LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
+ LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
+ }
+
+ stop_glerror();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ // render outline for HUD
+ if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
+ {
+ gGL.pushMatrix();
+ S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
+ S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
+ glScalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
+ glTranslatef((F32)half_width, (F32)half_height, 0.f);
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ glScalef(zoom,zoom,1.f);
+ gGL.color4fv(LLColor4::white.mV);
+ gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
+ gGL.popMatrix();
+ stop_glerror();
+ }
+
+
+ if (gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ if (LLUI::sDirty)
+ {
+ LLUI::sDirty = FALSE;
+ LLRect t_rect;
+
+ gPipeline.mUIScreen.bindTarget();
+ gGL.setColorMask(true, true);
+ {
+ static const S32 pad = 8;
+
+ LLUI::sDirtyRect.mLeft -= pad;
+ LLUI::sDirtyRect.mRight += pad;
+ LLUI::sDirtyRect.mBottom -= pad;
+ LLUI::sDirtyRect.mTop += pad;
+
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ static LLRect last_rect = LLUI::sDirtyRect;
+
+ //union with last rect to avoid mouse poop
+ last_rect.unionWith(LLUI::sDirtyRect);
+
+ t_rect = LLUI::sDirtyRect;
+ LLUI::sDirtyRect = last_rect;
+ last_rect = t_rect;
+
+ last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
+ last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
+ last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
+ last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
+
+ LLRect clip_rect(last_rect);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ gViewerWindow->draw();
+ }
+
+ gPipeline.mUIScreen.flush();
+ gGL.setColorMask(true, false);
+
+ LLUI::sDirtyRect = t_rect;
+ }
+
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ S32 width = gViewerWindow->getWindowWidthScaled();
+ S32 height = gViewerWindow->getWindowHeightScaled();
+ gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.color4f(1,1,1,1);
+ gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0);
+ gGL.texCoord2f(width, 0); gGL.vertex2i(width, 0);
+ gGL.texCoord2f(0, height); gGL.vertex2i(0, height);
+ gGL.texCoord2f(width, height); gGL.vertex2i(width, height);
+ gGL.end();
+ }
+ else
+ {
+ gViewerWindow->draw();
+ }
+
+
+
+ // reset current origin for font rendering, in case of tiling render
+ LLFontGL::sCurOrigin.set(0, 0);
+}
+
+void render_disconnected_background()
+{
+ gGL.color4f(1,1,1,1);
+ if (!gDisconnectedImagep && gDisconnected)
+ {
+ llinfos << "Loading last bitmap..." << llendl;
+
+ std::string temp_str;
+ temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME;
+
+ LLPointer<LLImageBMP> image_bmp = new LLImageBMP;
+ if( !image_bmp->load(temp_str) )
+ {
+ //llinfos << "Bitmap load failed" << llendl;
+ return;
+ }
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ if (!image_bmp->decode(raw, 0.0f))
+ {
+ llinfos << "Bitmap decode failed" << llendl;
+ gDisconnectedImagep = NULL;
+ return;
+ }
+
+ U8 *rawp = raw->getData();
+ S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight();
+ for (S32 i = 0; i < npixels; i++)
+ {
+ S32 sum = 0;
+ sum = *rawp + *(rawp+1) + *(rawp+2);
+ sum /= 3;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ *rawp = ((S32)sum*6 + *rawp)/7;
+ rawp++;
+ }
+
+
+ raw->expandToPowerOfTwo();
+ gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE );
+ gStartTexture = gDisconnectedImagep;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ // Make sure the progress view always fills the entire window.
+ S32 width = gViewerWindow->getWindowWidthScaled();
+ S32 height = gViewerWindow->getWindowHeightScaled();
+
+ if (gDisconnectedImagep)
+ {
+ LLGLSUIDefault gls_ui;
+ gViewerWindow->setup2DRender();
+ glPushMatrix();
+ {
+ // scale ui to reflect UIScaleFactor
+ // this can't be done in setup2DRender because it requires a
+ // pushMatrix/popMatrix pair
+ const LLVector2& display_scale = gViewerWindow->getDisplayScale();
+ glScalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
+
+ gGL.getTexUnit(0)->bind(gDisconnectedImagep);
+ gGL.color4f(1.f, 1.f, 1.f, 1.f);
+ gl_rect_2d_simple_tex(width, height);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+ glPopMatrix();
+ }
+ gGL.flush();
+}
+
+void display_cleanup()
+{
+ gDisconnectedImagep = NULL;
+}
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 6d3316cf6a..9d2b2f38c5 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2543,23 +2543,7 @@ bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
// Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
if( MASK_CONTROL & mask )
{
- if( 'C' == key )
- {
- mMediaSource->copy();
- result = true;
- }
- else
- if( 'V' == key )
- {
- mMediaSource->paste();
- result = true;
- }
- else
- if( 'X' == key )
- {
- mMediaSource->cut();
- result = true;
- }
+ result = true;
}
if(!result)
@@ -3000,7 +2984,8 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla
{
LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;
std::string url = plugin->getClickURL();
- LLURLDispatcher::dispatch(url, NULL, mTrustedBrowser);
+ std::string nav_type = plugin->getClickNavType();
+ LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser);
}
break;
case MEDIA_EVENT_CLICK_LINK_HREF:
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index de52aa17d1..4543a1ba9a 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -113,6 +113,11 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac
media_impl->focus(true);
gFocusMgr.setKeyboardFocus(this);
+ LLViewerMediaImpl* impl = getFocusedMediaImpl();
+ if (impl)
+ {
+ LLEditMenuHandler::gEditMenuHandler = impl;
+ }
// We must do this before processing the media HUD zoom, or it may zoom to the wrong face.
update();
@@ -139,6 +144,13 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac
{
gFocusMgr.setKeyboardFocus(NULL);
}
+
+ LLViewerMediaImpl* impl = getFocusedMediaImpl();
+ if (LLEditMenuHandler::gEditMenuHandler == impl)
+ {
+ LLEditMenuHandler::gEditMenuHandler = NULL;
+ }
+
mFocusedImplID = LLUUID::null;
if (objectp.notNull())
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index bb04973164..1764db48a2 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -865,40 +865,36 @@ void toggle_destination_and_avatar_picker(const LLSD& show)
LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn");
LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn");
- switch(panel_idx)
- {
- case 0:
- if (!destinations->getVisible())
- {
- container->setVisible(true);
- destinations->setVisible(true);
- avatar_picker->setVisible(false);
- LLFirstUse::notUsingDestinationGuide(false);
- avatar_btn->setToggleState(false);
- destination_btn->setToggleState(true);
- return;
- }
- break;
- case 1:
- if (!avatar_picker->getVisible())
- {
- container->setVisible(true);
- destinations->setVisible(false);
- avatar_picker->setVisible(true);
- avatar_btn->setToggleState(true);
- destination_btn->setToggleState(false);
- return;
- }
- break;
- default:
- break;
+ if (panel_idx == 0
+ && !destinations->getVisible())
+ { // opening destinations guide
+ container->setVisible(true);
+ destinations->setVisible(true);
+ avatar_picker->setVisible(false);
+ LLFirstUse::notUsingDestinationGuide(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(true);
+ gSavedSettings.setS32("DestinationsAndAvatarsVisibility", 0);
+ }
+ else if (panel_idx == 1
+ && !avatar_picker->getVisible())
+ { // opening avatar picker
+ container->setVisible(true);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(true);
+ avatar_btn->setToggleState(true);
+ destination_btn->setToggleState(false);
+ gSavedSettings.setS32("DestinationsAndAvatarsVisibility", 1);
+ }
+ else
+ { // toggling off dest guide or avatar picker
+ container->setVisible(false);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(false);
+ gSavedSettings.setS32("DestinationsAndAvatarsVisibility", -1);
}
-
- container->setVisible(false);
- destinations->setVisible(false);
- avatar_picker->setVisible(false);
- avatar_btn->setToggleState(false);
- destination_btn->setToggleState(false);
};
@@ -6443,12 +6439,12 @@ class LLToolsSelectedScriptAction : public view_listener_t
else if (action == "start")
{
name = "start_queue";
- msg = "Running";
+ msg = "SetRunning";
}
else if (action == "stop")
{
name = "stop_queue";
- msg = "RunningNot";
+ msg = "SetRunningNot";
}
LLUUID id; id.generate();
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index bb7f6453bc..fe9301d859 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -343,12 +343,6 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
{
LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
- if (!regionp || gNoRender)
- {
- return;
- }
-
-
S32 size;
S8 type;
@@ -2168,10 +2162,6 @@ void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string m
void process_improved_im(LLMessageSystem *msg, void **user_data)
{
- if (gNoRender)
- {
- return;
- }
LLUUID from_id;
BOOL from_group;
LLUUID to_id;
@@ -3960,7 +3950,9 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
// LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't
// trigger a control event.
U32 control_flags = gAgent.getControlFlags();
+
MASK key_mask = gKeyboard->currentMask(TRUE);
+
if (key_mask & MASK_ALT || key_mask & MASK_CONTROL)
{
control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN |
@@ -4279,7 +4271,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
gSky.setSunPhase(phase);
gSky.setSunTargetDirection(sun_direction, sun_ang_velocity);
- if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()))
+ if ( !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()) )
{
gSky.setSunDirection(sun_direction, sun_ang_velocity);
}
@@ -5541,21 +5533,12 @@ time_t gLastDisplayedTime = 0;
void handle_show_mean_events(void *)
{
- if (gNoRender)
- {
- return;
- }
LLFloaterReg::showInstance("bumps");
//LLFloaterBump::showInstance();
}
void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group)
{
- if (gNoRender)
- {
- return;
- }
-
static const U32 max_collision_list_size = 20;
if (gMeanCollisionList.size() > max_collision_list_size)
{
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index a5b59e8281..6d493bfcd5 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -482,11 +482,6 @@ void LLViewerObject::initVOClasses()
// Initialized shared class stuff first.
LLVOAvatar::initClass();
LLVOTree::initClass();
- if (gNoRender)
- {
- // Don't init anything else in drone mode
- return;
- }
llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl;
LLVOGrass::initClass();
LLVOWater::initClass();
@@ -2177,12 +2172,6 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
}
- if (gNoRender)
- {
- // Skip drawable stuff if not rendering.
- return TRUE;
- }
-
updateDrawable(FALSE);
return TRUE;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 0071753831..ab2e07e4df 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -637,19 +637,16 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
}
- if (!gNoRender)
+ // Slam priorities for textures that we care about (hovered, selected, and focused)
+ // Hovered
+ // Assumes only one level deep of parenting
+ LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+ if (nodep)
{
- // Slam priorities for textures that we care about (hovered, selected, and focused)
- // Hovered
- // Assumes only one level deep of parenting
- LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
- if (nodep)
+ objectp = nodep->getObject();
+ if (objectp)
{
- objectp = nodep->getObject();
- if (objectp)
- {
- objectp->boostTexturePriority();
- }
+ objectp->boostTexturePriority();
}
}
@@ -1466,7 +1463,7 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
// We need to update many object caches, I'll document this more as I dig through the code
// cleaning things out...
- if (gNoRender || 0 == offset.magVecSquared())
+ if (0 == offset.magVecSquared())
{
return;
}
@@ -1934,11 +1931,6 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip
void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
{
- if (gNoRender)
- {
- return;
- }
-
if (objectp->isDead())
{
llwarns << "Trying to find orphans for dead obj " << objectp->mID
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index 40f0b43313..dfa35edef4 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -539,6 +539,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
};
break;
+ case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;
+ };
+ break;
+
case MEDIA_EVENT_CLICK_LINK_HREF:
{
LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index fccd1156d3..e84e4a859a 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -1383,11 +1383,6 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
// static
void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user)
{
- if (gNoRender)
- {
- return;
- }
-
// Extract the packed overlay information
S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index dc0ee88554..84d092c5d5 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -73,8 +73,6 @@
#pragma warning(disable:4355)
#endif
-extern BOOL gNoRender;
-
const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region
const S16 MAX_MAP_DIST = 10;
@@ -111,7 +109,7 @@ public:
}
// Process the SLapp as if it was a secondlife://{PLACE} SLurl
- LLURLDispatcher::dispatch(url, web, true);
+ LLURLDispatcher::dispatch(url, "clicked", web, true);
return true;
}
};
@@ -235,28 +233,19 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
updateRenderMatrix();
mLandp = new LLSurface('l', NULL);
- if (!gNoRender)
- {
- // Create the composition layer for the surface
- mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge);
- mCompositionp->setSurface(mLandp);
-
- // Create the surfaces
- mLandp->setRegion(this);
- mLandp->create(grids_per_region_edge,
- grids_per_patch_edge,
- mOriginGlobal,
- mWidth);
- }
- if (!gNoRender)
- {
- mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
- }
- else
- {
- mParcelOverlay = NULL;
- }
+ // Create the composition layer for the surface
+ mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge);
+ mCompositionp->setSurface(mLandp);
+
+ // Create the surfaces
+ mLandp->setRegion(this);
+ mLandp->create(grids_per_region_edge,
+ grids_per_patch_edge,
+ mOriginGlobal,
+ mWidth);
+
+ mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
setOriginGlobal(from_region_handle(handle));
calculateCenterGlobal();
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 221d1114a7..0fb94bc44b 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -712,7 +712,7 @@ void send_stats()
// but that day is not today.
// Only send stats if the agent is connected to a region.
- if (!gAgent.getRegion() || gNoRender)
+ if (!gAgent.getRegion())
{
return;
}
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5cd2881e2a..af06421bf9 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1415,70 +1415,68 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize())
// << mID.getString() << llendl;
BOOL res = TRUE;
- if (!gNoRender)
+
+ // store original size only for locally-sourced images
+ if (mUrl.compare(0, 7, "file://") == 0)
{
- // store original size only for locally-sourced images
- if (mUrl.compare(0, 7, "file://") == 0)
- {
- mOrigWidth = mRawImage->getWidth();
- mOrigHeight = mRawImage->getHeight();
+ mOrigWidth = mRawImage->getWidth();
+ mOrigHeight = mRawImage->getHeight();
- if (mBoostLevel == BOOST_PREVIEW)
- {
- mRawImage->biasedScaleToPowerOfTwo(1024);
- }
- else
- { // leave black border, do not scale image content
- mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
- }
-
- mFullWidth = mRawImage->getWidth();
- mFullHeight = mRawImage->getHeight();
- setTexelsPerImage();
+ if (mBoostLevel == BOOST_PREVIEW)
+ {
+ mRawImage->biasedScaleToPowerOfTwo(1024);
}
else
- {
- mOrigWidth = mFullWidth;
- mOrigHeight = mFullHeight;
+ { // leave black border, do not scale image content
+ mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
}
-
- bool size_okay = true;
- U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel;
- U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel;
- if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE )
- {
- llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl;
- size_okay = false;
- }
-
- if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
- {
- // A non power-of-two image was uploaded (through a non standard client)
- llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl;
- size_okay = false;
- }
-
- if( !size_okay )
- {
- // An inappropriately-sized image was uploaded (through a non standard client)
- // We treat these images as missing assets which causes them to
- // be renderd as 'missing image' and to stop requesting data
- setIsMissingAsset();
- destroyRawImage();
- return FALSE;
- }
-
- if(!(res = insertToAtlas()))
- {
- res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
- resetFaceAtlas() ;
- }
- setActive() ;
+ mFullWidth = mRawImage->getWidth();
+ mFullHeight = mRawImage->getHeight();
+ setTexelsPerImage();
+ }
+ else
+ {
+ mOrigWidth = mFullWidth;
+ mOrigHeight = mFullHeight;
+ }
+
+ bool size_okay = true;
+
+ U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel;
+ U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel;
+ if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE )
+ {
+ llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl;
+ size_okay = false;
+ }
+
+ if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight()))
+ {
+ // A non power-of-two image was uploaded (through a non standard client)
+ llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl;
+ size_okay = false;
+ }
+
+ if( !size_okay )
+ {
+ // An inappropriately-sized image was uploaded (through a non standard client)
+ // We treat these images as missing assets which causes them to
+ // be renderd as 'missing image' and to stop requesting data
+ setIsMissingAsset();
+ destroyRawImage();
+ return FALSE;
+ }
+
+ if(!(res = insertToAtlas()))
+ {
+ res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
+ resetFaceAtlas() ;
}
+ setActive() ;
- if (!mForceToSaveRawImage)
+ if (!needsToSaveRawImage())
{
mNeedsAux = FALSE;
destroyRawImage();
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index b5eadb6d25..76c6c3512e 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -91,11 +91,6 @@ void LLViewerTextureList::init()
sNumImages = 0;
mMaxResidentTexMemInMegaBytes = 0;
mMaxTotalTextureMemInMegaBytes = 0 ;
- if (gNoRender)
- {
- // Don't initialize GL stuff if we're not rendering.
- return;
- }
mUpdateStats = TRUE;
@@ -345,13 +340,6 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
LLGLenum primary_format,
const LLUUID& force_id)
{
- if (gNoRender)
- {
- // Never mind that this ignores image_set_id;
- // getImage() will handle that later.
- return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLViewerTexture::BOOST_UI);
- }
-
// generate UUID based on hash of filename
LLUUID new_id;
if (force_id.notNull())
@@ -741,7 +729,7 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create Images");
F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
{
- if (gNoRender || gGLManager.mIsDisabled) return 0.0f;
+ if (gGLManager.mIsDisabled) return 0.0f;
//
// Create GL textures for all textures that need them (images which have been
@@ -876,7 +864,6 @@ void LLViewerTextureList::updateImagesUpdateStats()
void LLViewerTextureList::decodeAllImages(F32 max_time)
{
LLTimer timer;
- if(gNoRender) return;
// Update texture stats and priorities
std::vector<LLPointer<LLViewerFetchedTexture> > image_list;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index b946dbbd0f..88e6cf3dbe 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1069,7 +1069,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
{
if (drop)
{
- LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true );
+ LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), "clicked", NULL, true );
return LLWindowCallbacks::DND_MOVE;
}
return LLWindowCallbacks::DND_COPY;
@@ -1395,8 +1395,9 @@ void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
{
+ // *TODO: Enable similar information output for other platforms? DK 2011-02-18
#if LL_WINDOWS
- if (gNoRender)
+ if (gHeadlessClient)
{
HWND window_handle = (HWND)window->getPlatformWindow();
PAINTSTRUCT ps;
@@ -1426,7 +1427,7 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S
len = temp_str.length();
TextOutA(hdc, 0, 25, temp_str.c_str(), len);
- TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
+ TextOutA(hdc, 0, 50, "Set \"HeadlessClient FALSE\" in settings.ini file to reenable", 61);
EndPaint(window_handle, &ps);
return TRUE;
}
@@ -1460,7 +1461,8 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
std::string url = (const char*)data;
LLMediaCtrl* web = NULL;
const bool trusted_browser = false;
- if (LLURLDispatcher::dispatch(url, web, trusted_browser))
+ // don't treat slapps coming from external browsers as "clicks" as this would bypass throttling
+ if (LLURLDispatcher::dispatch(url, "", web, trusted_browser))
{
// bring window to foreground, as it has just been "launched" from a URL
mWindow->bringToFront();
@@ -1574,9 +1576,9 @@ LLViewerWindow::LLViewerWindow(
mWindow = LLWindowManager::createWindow(this,
title, name, x, y, width, height, 0,
fullscreen,
- gNoRender,
+ gHeadlessClient,
gSavedSettings.getBOOL("DisableVerticalSync"),
- !gNoRender,
+ !gHeadlessClient,
ignore_pixel_depth,
gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
@@ -1945,19 +1947,18 @@ void LLViewerWindow::initWorldUI()
LLMediaCtrl* avatar_picker = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("avatar_picker_contents");
if (destinations)
{
+ destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html");
}
if (avatar_picker)
{
+ avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html");
}
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- toggle_destination_and_avatar_picker(0);
- gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE);
- }
+ // show destinations by default
+ toggle_destination_and_avatar_picker(gSavedSettings.getS32("DestinationsAndAvatarsVisibility"));
}
// Destroy the UI
@@ -2039,11 +2040,8 @@ void LLViewerWindow::shutdownGL()
LLVertexBuffer::cleanupClass();
llinfos << "Stopping GL during shutdown" << llendl;
- if (!gNoRender)
- {
- stopGL(FALSE);
- stop_glerror();
- }
+ stopGL(FALSE);
+ stop_glerror();
gGL.shutdown();
}
@@ -2107,11 +2105,6 @@ void LLViewerWindow::reshape(S32 width, S32 height)
// may have been destructed.
if (!LLApp::isExiting())
{
- if (gNoRender)
- {
- return;
- }
-
gWindowResized = TRUE;
// update our window rectangle
@@ -2748,12 +2741,8 @@ void LLViewerWindow::updateUI()
S32 x = mCurrentMousePoint.mX;
S32 y = mCurrentMousePoint.mY;
- MASK mask = gKeyboard->currentMask(TRUE);
- if (gNoRender)
- {
- return;
- }
+ MASK mask = gKeyboard->currentMask(TRUE);
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
@@ -3146,7 +3135,8 @@ void LLViewerWindow::updateLayout()
}
// Update the location of the blue box tool popup
LLCoordGL select_center_screen;
- gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) );
+ MASK mask = gKeyboard->currentMask(TRUE);
+ gFloaterTools->updatePopup( select_center_screen, mask );
}
else
{
@@ -3272,7 +3262,8 @@ void LLViewerWindow::updateKeyboardFocus()
// sync all floaters with their focus state
gFloaterView->highlightFocusedFloater();
gSnapshotFloaterView->highlightFocusedFloater();
- if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
+ MASK mask = gKeyboard->currentMask(TRUE);
+ if ((mask & MASK_CONTROL) == 0)
{
// control key no longer held down, finish cycle mode
gFloaterView->setCycleMode(FALSE);
@@ -3585,11 +3576,6 @@ BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewe
void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent)
{
- if (gNoRender)
- {
- return;
- }
-
BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
{
@@ -3625,11 +3611,6 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
void LLViewerWindow::performPick()
{
- if (gNoRender)
- {
- return;
- }
-
if (!mPicks.empty())
{
std::vector<LLPickInfo>::iterator pick_it;
@@ -3661,11 +3642,6 @@ void LLViewerWindow::returnEmptyPicks()
// Performs the GL object/land pick.
LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
{
- if (gNoRender)
- {
- return LLPickInfo();
- }
-
BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
{
@@ -3675,7 +3651,8 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans
}
// shortcut queueing in mPicks and just update mLastPick in place
- mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL);
+ MASK key_mask = gKeyboard->currentMask(TRUE);
+ mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL);
mLastPick.fetchResults();
return mLastPick;
@@ -4949,12 +4926,9 @@ bool LLViewerWindow::onAlert(const LLSD& notify)
{
LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
- if (gNoRender)
+ if (gHeadlessClient)
{
llinfos << "Alert: " << notification->getName() << llendl;
- notification->respond(LLSD::emptyMap());
- LLNotifications::instance().cancel(notification);
- return false;
}
// If we're in mouselook, the mouse is hidden and so the user can't click
diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp
index 0b52948680..1fe5fc9800 100644
--- a/indra/newview/llviewerwindowlistener.cpp
+++ b/indra/newview/llviewerwindowlistener.cpp
@@ -65,7 +65,6 @@ LLViewerWindowListener::LLViewerWindowListener(LLViewerWindow* llviewerwindow):
void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
{
- LLReqID reqid(event);
typedef std::map<LLSD::String, LLViewerWindow::ESnapshotType> TypeMap;
TypeMap types;
#define tp(name) types[#name] = LLViewerWindow::SNAPSHOT_TYPE_##name
@@ -98,9 +97,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const
type = found->second;
}
bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, rebuild, type);
- LLSD response(reqid.makeResponse());
- response["ok"] = ok;
- LLEventPumps::instance().obtain(event["reply"]).post(response);
+ sendReply(LLSDMap("ok", ok), event);
}
void LLViewerWindowListener::requestReshape(LLSD const & event_data) const
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 58fe7e673e..1f6d686a86 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1,8466 +1,8417 @@
-/**
- * @File llvoavatar.cpp
- * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject
- *
- * $LicenseInfo:firstyear=2001&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$
- */
-
-#if LL_MSVC
-// disable warning about boost::lexical_cast returning uninitialized data
-// when it fails to parse the string
-#pragma warning (disable:4701)
-#endif
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llvoavatar.h"
-
-#include <stdio.h>
-#include <ctype.h>
-
-#include "llaudioengine.h"
-#include "llcachename.h"
-#include "noise.h"
-#include "sound_ids.h"
-
-#include "llagent.h" // Get state values from here
-#include "llagentcamera.h"
-#include "llagentwearables.h"
-#include "llanimationstates.h"
-#include "llavatarnamecache.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llphysicsmotion.h"
-#include "llviewercontrol.h"
-#include "llcallingcard.h" // IDEVO for LLAvatarTracker
-#include "lldrawpoolavatar.h"
-#include "lldriverparam.h"
-#include "lleditingmotion.h"
-#include "llemote.h"
-//#include "llfirstuse.h"
-#include "llheadrotmotion.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llhudnametag.h"
-#include "llhudtext.h" // for mText/mDebugText
-#include "llkeyframefallmotion.h"
-#include "llkeyframestandmotion.h"
-#include "llkeyframewalkmotion.h"
-#include "llmanipscale.h" // for get_default_max_prim_scale()
-#include "llmeshrepository.h"
-#include "llmutelist.h"
-#include "llmoveview.h"
-#include "llnotificationsutil.h"
-#include "llquantize.h"
-#include "llrand.h"
-#include "llregionhandle.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llsprite.h"
-#include "lltargetingmotion.h"
-#include "lltexlayer.h"
-#include "lltoolmorph.h"
-#include "llviewercamera.h"
-#include "llviewertexturelist.h"
-#include "llviewermenu.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llvoavatarself.h"
-#include "llvovolume.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "llviewershadermgr.h"
-#include "llsky.h"
-#include "llanimstatelabels.h"
-#include "lltrans.h"
-#include "llappearancemgr.h"
-
-#include "llgesturemgr.h" //needed to trigger the voice gesticulations
-#include "llvoiceclient.h"
-#include "llvoicevisualizer.h" // Ventrella
-
-#include "lldebugmessagebox.h"
-extern F32 SPEED_ADJUST_MAX;
-extern F32 SPEED_ADJUST_MAX_SEC;
-extern F32 ANIM_SPEED_MAX;
-extern F32 ANIM_SPEED_MIN;
-
-#if LL_MSVC
-// disable boost::lexical_cast warning
-#pragma warning (disable:4702)
-#endif
-
-#include <boost/lexical_cast.hpp>
-
-// #define OUTPUT_BREAST_DATA
-
-using namespace LLVOAvatarDefines;
-
-//-----------------------------------------------------------------------------
-// Global constants
-//-----------------------------------------------------------------------------
-const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise"
-const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot"
-const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing"
-const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye"
-const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust"
-const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion"
-const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot"
-const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix"
-const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target"
-const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust"
-const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion"
-
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-const std::string AVATAR_DEFAULT_CHAR = "avatar";
-
-const S32 MIN_PIXEL_AREA_FOR_COMPOSITE = 1024;
-const F32 SHADOW_OFFSET_AMT = 0.03f;
-
-const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this
-const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations.
-
-const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying
-const F32 PELVIS_LAG_WALKING = 0.4f; // ...while walking
-const F32 PELVIS_LAG_MOUSELOOK = 0.15f;
-const F32 MOUSELOOK_PELVIS_FOLLOW_FACTOR = 0.5f;
-const F32 PELVIS_LAG_WHEN_FOLLOW_CAM_IS_ON = 0.0001f; // not zero! - something gets divided by this!
-
-const F32 PELVIS_ROT_THRESHOLD_SLOW = 60.0f; // amount of deviation allowed between
-const F32 PELVIS_ROT_THRESHOLD_FAST = 2.0f; // the pelvis and the view direction
- // when moving fast & slow
-const F32 TORSO_NOISE_AMOUNT = 1.0f; // Amount of deviation from up-axis, in degrees
-const F32 TORSO_NOISE_SPEED = 0.2f; // Time scale factor on torso noise.
-
-const F32 BREATHE_ROT_MOTION_STRENGTH = 0.05f;
-const F32 BREATHE_SCALE_MOTION_STRENGTH = 0.005f;
-
-const F32 MIN_SHADOW_HEIGHT = 0.f;
-const F32 MAX_SHADOW_HEIGHT = 0.3f;
-
-const S32 MIN_REQUIRED_PIXEL_AREA_BODY_NOISE = 10000;
-const S32 MIN_REQUIRED_PIXEL_AREA_BREATHE = 10000;
-const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40;
-
-const S32 TEX_IMAGE_SIZE_SELF = 512;
-const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF;
-const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars
-
-const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
-
-const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
-
-// Discard level at which to switch to baked textures
-// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
-const S32 SWITCH_TO_BAKED_DISCARD = 5;
-
-const F32 FOOT_COLLIDE_FUDGE = 0.04f;
-
-const F32 HOVER_EFFECT_MAX_SPEED = 3.f;
-const F32 HOVER_EFFECT_STRENGTH = 0.f;
-const F32 UNDERWATER_EFFECT_STRENGTH = 0.1f;
-const F32 UNDERWATER_FREQUENCY_DAMP = 0.33f;
-const F32 APPEARANCE_MORPH_TIME = 0.65f;
-const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds
-const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory
-const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f;
-const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f;
-const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN;
-const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12;
-const F32 CHAT_FADE_TIME = 8.0;
-const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f;
-
-const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
-
-enum ERenderName
-{
- RENDER_NAME_NEVER,
- RENDER_NAME_ALWAYS,
- RENDER_NAME_FADE
-};
-
-//-----------------------------------------------------------------------------
-// Callback data
-//-----------------------------------------------------------------------------
-
-struct LLTextureMaskData
-{
- LLTextureMaskData( const LLUUID& id ) :
- mAvatarID(id),
- mLastDiscardLevel(S32_MAX)
- {}
- LLUUID mAvatarID;
- S32 mLastDiscardLevel;
-};
-
-/*********************************************************************************
- ** **
- ** Begin private LLVOAvatar Support classes
- **
- **/
-
-//------------------------------------------------------------------------
-// LLVOBoneInfo
-// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
-//------------------------------------------------------------------------
-class LLVOAvatarBoneInfo
-{
- friend class LLVOAvatar;
- friend class LLVOAvatarSkeletonInfo;
-public:
- LLVOAvatarBoneInfo() : mIsJoint(FALSE) {}
- ~LLVOAvatarBoneInfo()
- {
- std::for_each(mChildList.begin(), mChildList.end(), DeletePointer());
- }
- BOOL parseXml(LLXmlTreeNode* node);
-
-private:
- std::string mName;
- BOOL mIsJoint;
- LLVector3 mPos;
- LLVector3 mRot;
- LLVector3 mScale;
- LLVector3 mPivot;
- typedef std::vector<LLVOAvatarBoneInfo*> child_list_t;
- child_list_t mChildList;
-};
-
-//------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo
-// Overall avatar skeleton
-//------------------------------------------------------------------------
-class LLVOAvatarSkeletonInfo
-{
- friend class LLVOAvatar;
-public:
- LLVOAvatarSkeletonInfo() :
- mNumBones(0), mNumCollisionVolumes(0) {}
- ~LLVOAvatarSkeletonInfo()
- {
- std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
- }
- BOOL parseXml(LLXmlTreeNode* node);
- S32 getNumBones() const { return mNumBones; }
- S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
-
-private:
- S32 mNumBones;
- S32 mNumCollisionVolumes;
- typedef std::vector<LLVOAvatarBoneInfo*> bone_info_list_t;
- bone_info_list_t mBoneInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// class LLBodyNoiseMotion
-//-----------------------------------------------------------------------------
-class LLBodyNoiseMotion :
- public LLMotion
-{
-public:
- // Constructor
- LLBodyNoiseMotion(const LLUUID &id)
- : LLMotion(id)
- {
- mName = "body_noise";
- mTorsoState = new LLJointState;
- }
-
- // Destructor
- virtual ~LLBodyNoiseMotion() { }
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual BOOL getLoop() { return TRUE; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 0.0; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 0.0; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BODY_NOISE; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character)
- {
- if( !mTorsoState->setJoint( character->getJoint("mTorso") ))
- {
- return STATUS_FAILURE;
- }
-
- mTorsoState->setUsage(LLJointState::ROT);
-
- addJointState( mTorsoState );
- return STATUS_SUCCESS;
- }
-
- // called when a motion is activated
- // must return TRUE to indicate success, or else
- // it will be deactivated
- virtual BOOL onActivate() { return TRUE; }
-
- // called per time step
- // must return TRUE while it is active, and
- // must return FALSE when the motion is completed.
- virtual BOOL onUpdate(F32 time, U8* joint_mask)
- {
- F32 nx[2];
- nx[0]=time*TORSO_NOISE_SPEED;
- nx[1]=0.0f;
- F32 ny[2];
- ny[0]=0.0f;
- ny[1]=time*TORSO_NOISE_SPEED;
- F32 noiseX = noise2(nx);
- F32 noiseY = noise2(ny);
-
- F32 rx = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseX / 0.42f;
- F32 ry = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseY / 0.42f;
- LLQuaternion tQn;
- tQn.setQuat( rx, ry, 0.0f );
- mTorsoState->setRotation( tQn );
-
- return TRUE;
- }
-
- // called when a motion is deactivated
- virtual void onDeactivate() {}
-
-private:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LLPointer<LLJointState> mTorsoState;
-};
-
-//-----------------------------------------------------------------------------
-// class LLBreatheMotionRot
-//-----------------------------------------------------------------------------
-class LLBreatheMotionRot :
- public LLMotion
-{
-public:
- // Constructor
- LLBreatheMotionRot(const LLUUID &id) :
- LLMotion(id),
- mBreatheRate(1.f),
- mCharacter(NULL)
- {
- mName = "breathe_rot";
- mChestState = new LLJointState;
- }
-
- // Destructor
- virtual ~LLBreatheMotionRot() {}
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual BOOL getLoop() { return TRUE; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 0.0; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 0.0; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BREATHE; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character)
- {
- mCharacter = character;
- BOOL success = true;
-
- if ( !mChestState->setJoint( character->getJoint( "mChest" ) ) ) { success = false; }
-
- if ( success )
- {
- mChestState->setUsage(LLJointState::ROT);
- addJointState( mChestState );
- }
-
- if ( success )
- {
- return STATUS_SUCCESS;
- }
- else
- {
- return STATUS_FAILURE;
- }
- }
-
- // called when a motion is activated
- // must return TRUE to indicate success, or else
- // it will be deactivated
- virtual BOOL onActivate() { return TRUE; }
-
- // called per time step
- // must return TRUE while it is active, and
- // must return FALSE when the motion is completed.
- virtual BOOL onUpdate(F32 time, U8* joint_mask)
- {
- mBreatheRate = 1.f;
-
- F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
-
- mChestState->setRotation(LLQuaternion(breathe_amt, LLVector3(0.f, 1.f, 0.f)));
-
- return TRUE;
- }
-
- // called when a motion is deactivated
- virtual void onDeactivate() {}
-
-private:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LLPointer<LLJointState> mChestState;
- F32 mBreatheRate;
- LLCharacter* mCharacter;
-};
-
-//-----------------------------------------------------------------------------
-// class LLPelvisFixMotion
-//-----------------------------------------------------------------------------
-class LLPelvisFixMotion :
- public LLMotion
-{
-public:
- // Constructor
- LLPelvisFixMotion(const LLUUID &id)
- : LLMotion(id), mCharacter(NULL)
- {
- mName = "pelvis_fix";
-
- mPelvisState = new LLJointState;
- }
-
- // Destructor
- virtual ~LLPelvisFixMotion() { }
-
-public:
- //-------------------------------------------------------------------------
- // functions to support MotionController and MotionRegistry
- //-------------------------------------------------------------------------
- // static constructor
- // all subclasses must implement such a function and register it
- static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); }
-
-public:
- //-------------------------------------------------------------------------
- // animation callbacks to be implemented by subclasses
- //-------------------------------------------------------------------------
-
- // motions must specify whether or not they loop
- virtual BOOL getLoop() { return TRUE; }
-
- // motions must report their total duration
- virtual F32 getDuration() { return 0.0; }
-
- // motions must report their "ease in" duration
- virtual F32 getEaseInDuration() { return 0.5f; }
-
- // motions must report their "ease out" duration.
- virtual F32 getEaseOutDuration() { return 0.5f; }
-
- // motions must report their priority
- virtual LLJoint::JointPriority getPriority() { return LLJoint::LOW_PRIORITY; }
-
- virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
-
- // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
- virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX; }
-
- // run-time (post constructor) initialization,
- // called after parameters have been set
- // must return true to indicate success and be available for activation
- virtual LLMotionInitStatus onInitialize(LLCharacter *character)
- {
- mCharacter = character;
-
- if (!mPelvisState->setJoint( character->getJoint("mPelvis")))
- {
- return STATUS_FAILURE;
- }
-
- mPelvisState->setUsage(LLJointState::POS);
-
- addJointState( mPelvisState );
- return STATUS_SUCCESS;
- }
-
- // called when a motion is activated
- // must return TRUE to indicate success, or else
- // it will be deactivated
- virtual BOOL onActivate() { return TRUE; }
-
- // called per time step
- // must return TRUE while it is active, and
- // must return FALSE when the motion is completed.
- virtual BOOL onUpdate(F32 time, U8* joint_mask)
- {
- mPelvisState->setPosition(LLVector3::zero);
-
- return TRUE;
- }
-
- // called when a motion is deactivated
- virtual void onDeactivate() {}
-
-private:
- //-------------------------------------------------------------------------
- // joint states to be animated
- //-------------------------------------------------------------------------
- LLPointer<LLJointState> mPelvisState;
- LLCharacter* mCharacter;
-};
-
-/**
- **
- ** End LLVOAvatar Support classes
- ** **
- *********************************************************************************/
-
-
-//-----------------------------------------------------------------------------
-// Static Data
-//-----------------------------------------------------------------------------
-LLXmlTree LLVOAvatar::sXMLTree;
-LLXmlTree LLVOAvatar::sSkeletonXMLTree;
-LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL;
-LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL;
-LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL;
-S32 LLVOAvatar::sFreezeCounter = 0;
-U32 LLVOAvatar::sMaxVisible = 12;
-F32 LLVOAvatar::sRenderDistance = 256.f;
-S32 LLVOAvatar::sNumVisibleAvatars = 0;
-S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
-
-const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df");
-const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] =
-{
- SND_STONE_RUBBER,
- SND_METAL_RUBBER,
- SND_GLASS_RUBBER,
- SND_WOOD_RUBBER,
- SND_FLESH_RUBBER,
- SND_RUBBER_PLASTIC,
- SND_RUBBER_RUBBER
-};
-
-S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS;
-BOOL LLVOAvatar::sRenderGroupTitles = TRUE;
-S32 LLVOAvatar::sNumVisibleChatBubbles = 0;
-BOOL LLVOAvatar::sDebugInvisible = FALSE;
-BOOL LLVOAvatar::sShowAttachmentPoints = FALSE;
-BOOL LLVOAvatar::sShowAnimationDebug = FALSE;
-BOOL LLVOAvatar::sShowFootPlane = FALSE;
-BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
-F32 LLVOAvatar::sLODFactor = 1.f;
-F32 LLVOAvatar::sPhysicsLODFactor = 1.f;
-BOOL LLVOAvatar::sUseImpostors = FALSE;
-BOOL LLVOAvatar::sJointDebug = FALSE;
-
-F32 LLVOAvatar::sUnbakedTime = 0.f;
-F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
-F32 LLVOAvatar::sGreyTime = 0.f;
-F32 LLVOAvatar::sGreyUpdateTime = 0.f;
-
-//-----------------------------------------------------------------------------
-// Helper functions
-//-----------------------------------------------------------------------------
-static F32 calc_bouncy_animation(F32 x);
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar()
-//-----------------------------------------------------------------------------
-LLVOAvatar::LLVOAvatar(const LLUUID& id,
- const LLPCode pcode,
- LLViewerRegion* regionp) :
- LLViewerObject(id, pcode, regionp),
- mIsDummy(FALSE),
- mSpecialRenderMode(0),
- mTurning(FALSE),
- mPelvisToFoot(0.f),
- mLastSkeletonSerialNum( 0 ),
- mHeadOffset(),
- mIsSitting(FALSE),
- mTimeVisible(),
- mTyping(FALSE),
- mMeshValid(FALSE),
- mVisible(FALSE),
- mWindFreq(0.f),
- mRipplePhase( 0.f ),
- mBelowWater(FALSE),
- mLastAppearanceBlendTime(0.f),
- mAppearanceAnimating(FALSE),
- mNameString(),
- mTitle(),
- mNameAway(false),
- mNameBusy(false),
- mNameMute(false),
- mNameAppearance(false),
- mNameFriend(false),
- mNameAlpha(0.f),
- mRenderGroupTitles(sRenderGroupTitles),
- mNameCloud(false),
- mFirstTEMessageReceived( FALSE ),
- mFirstAppearanceMessageReceived( FALSE ),
- mCulled( FALSE ),
- mVisibilityRank(0),
- mTexSkinColor( NULL ),
- mTexHairColor( NULL ),
- mTexEyeColor( NULL ),
- mNeedsSkin(FALSE),
- mLastSkinTime(0.f),
- mUpdatePeriod(1),
- mFullyLoaded(FALSE),
- mPreviousFullyLoaded(FALSE),
- mFullyLoadedInitialized(FALSE),
- mSupportsAlphaLayers(FALSE),
- mLoadedCallbacksPaused(FALSE),
- mHasPelvisOffset( FALSE )
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
- //VTResume(); // VTune
-
- // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline
- const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
- mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
-
- lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl;
-
- mPelvisp = NULL;
-
- mBakedTextureDatas.resize(BAKED_NUM_INDICES);
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
- {
- mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR;
- mBakedTextureDatas[i].mTexLayerSet = NULL;
- mBakedTextureDatas[i].mIsLoaded = false;
- mBakedTextureDatas[i].mIsUsed = false;
- mBakedTextureDatas[i].mMaskTexName = 0;
- mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i);
- }
-
- mDirtyMesh = 2; // Dirty geometry, need to regenerate.
- mMeshTexturesDirty = FALSE;
- mHeadp = NULL;
-
- mIsBuilt = FALSE;
-
- mNumJoints = 0;
- mSkeleton = NULL;
-
- mNumCollisionVolumes = 0;
- mCollisionVolumes = NULL;
-
- // set up animation variables
- mSpeed = 0.f;
- setAnimationData("Speed", &mSpeed);
-
- mNeedsImpostorUpdate = TRUE;
- mNeedsAnimUpdate = TRUE;
-
- mImpostorDistance = 0;
- mImpostorPixelArea = 0;
-
- setNumTEs(TEX_NUM_INDICES);
-
- mbCanSelect = TRUE;
-
- mSignaledAnimations.clear();
- mPlayingAnimations.clear();
-
- mWasOnGroundLeft = FALSE;
- mWasOnGroundRight = FALSE;
-
- mTimeLast = 0.0f;
- mSpeedAccum = 0.0f;
-
- mRippleTimeLast = 0.f;
-
- mInAir = FALSE;
-
- mStepOnLand = TRUE;
- mStepMaterial = 0;
-
- mLipSyncActive = false;
- mOohMorph = NULL;
- mAahMorph = NULL;
-
- mCurrentGesticulationLevel = 0;
-
- mRuthTimer.reset();
- mRuthDebugTimer.reset();
- mDebugExistenceTimer.reset();
- mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
- mLastPelvisToFoot = 0.0f;
- mPelvisFixup = 0.0f;
- mLastPelvisFixup = 0.0f;
-}
-
-//------------------------------------------------------------------------
-// LLVOAvatar::~LLVOAvatar()
-//------------------------------------------------------------------------
-LLVOAvatar::~LLVOAvatar()
-{
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- if (!mFullyLoaded)
- {
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl;
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args);
- }
- else
- {
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl;
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezLeftNotification",args);
- }
-
- }
- lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
-
- mRoot.removeAllChildren();
-
- deleteAndClearArray(mSkeleton);
- deleteAndClearArray(mCollisionVolumes);
-
- mNumJoints = 0;
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- deleteAndClear(mBakedTextureDatas[i].mTexLayerSet);
- mBakedTextureDatas[i].mMeshes.clear();
-
- for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin();
- iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++)
- {
- LLMaskedMorph* masked_morph = (*iter2);
- delete masked_morph;
- }
- }
-
- std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
- mAttachmentPoints.clear();
-
- deleteAndClear(mTexSkinColor);
- deleteAndClear(mTexHairColor);
- deleteAndClear(mTexEyeColor);
-
- std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer());
- mMeshes.clear();
-
- for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
- jointIter != mMeshLOD.end();
- ++jointIter)
- {
- LLViewerJoint* joint = (LLViewerJoint *) *jointIter;
- std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
- joint->mMeshParts.clear();
- }
- std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
- mMeshLOD.clear();
-
- mDead = TRUE;
-
- mAnimationSources.clear();
- LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
-
- lldebugs << "LLVOAvatar Destructor end" << llendl;
-}
-
-void LLVOAvatar::markDead()
-{
- if (mNameText)
- {
- mNameText->markDead();
- mNameText = NULL;
- sNumVisibleChatBubbles--;
- }
- mVoiceVisualizer->markDead();
- LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
- LLViewerObject::markDead();
-}
-
-
-BOOL LLVOAvatar::isFullyBaked()
-{
- if (mIsDummy) return TRUE;
- if (getNumTEs() == 0) return FALSE;
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex)
- && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) )
- {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-void LLVOAvatar::deleteLayerSetCaches(bool clearAll)
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- if (mBakedTextureDatas[i].mTexLayerSet)
- {
- // ! BACKWARDS COMPATIBILITY !
- // Can be removed after hair baking is mandatory on the grid
- if ((i != BAKED_HAIR || isSelf()) && !clearAll)
- {
- mBakedTextureDatas[i].mTexLayerSet->deleteCaches();
- }
- }
- if (mBakedTextureDatas[i].mMaskTexName)
- {
- glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName));
- mBakedTextureDatas[i].mMaskTexName = 0 ;
- }
- }
-}
-
-// static
-BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars)
-{
- BOOL res = TRUE;
- grey_avatars = 0;
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* inst = (LLVOAvatar*) *iter;
- if( inst->isDead() )
- {
- continue;
- }
- else if( !inst->isFullyBaked() )
- {
- res = FALSE;
- if (inst->mHasGrey)
- {
- ++grey_avatars;
- }
- }
- }
- return res;
-}
-
-// static
-void LLVOAvatar::dumpBakedStatus()
-{
- LLVector3d camera_pos_global = gAgentCamera.getCameraPositionGlobal();
-
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* inst = (LLVOAvatar*) *iter;
- llinfos << "Avatar ";
-
- LLNameValue* firstname = inst->getNVPair("FirstName");
- LLNameValue* lastname = inst->getNVPair("LastName");
-
- if( firstname )
- {
- llcont << firstname->getString();
- }
- if( lastname )
- {
- llcont << " " << lastname->getString();
- }
-
- llcont << " " << inst->mID;
-
- if( inst->isDead() )
- {
- llcont << " DEAD ("<< inst->getNumRefs() << " refs)";
- }
-
- if( inst->isSelf() )
- {
- llcont << " (self)";
- }
-
-
- F64 dist_to_camera = (inst->getPositionGlobal() - camera_pos_global).length();
- llcont << " " << dist_to_camera << "m ";
-
- llcont << " " << inst->mPixelArea << " pixels";
-
- if( inst->isVisible() )
- {
- llcont << " (visible)";
- }
- else
- {
- llcont << " (not visible)";
- }
-
- if( inst->isFullyBaked() )
- {
- llcont << " Baked";
- }
- else
- {
- llcont << " Unbaked (";
-
- for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
- iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
- ++iter)
- {
- const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second;
- const ETextureIndex index = baked_dict->mTextureIndex;
- if (!inst->isTextureDefined(index))
- {
- llcont << " " << LLVOAvatarDictionary::getInstance()->getTexture(index)->mName;
- }
- }
- llcont << " ) " << inst->getUnbakedPixelAreaRank();
- if( inst->isCulled() )
- {
- llcont << " culled";
- }
- }
- llcont << llendl;
- }
-}
-
-//static
-void LLVOAvatar::restoreGL()
-{
- if (!isAgentAvatarValid()) return;
-
- gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
- for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)
- {
- gAgentAvatarp->invalidateComposite(gAgentAvatarp->mBakedTextureDatas[i].mTexLayerSet, FALSE);
- }
- gAgentAvatarp->updateMeshTextures();
-}
-
-//static
-void LLVOAvatar::destroyGL()
-{
- deleteCachedImages();
-
- resetImpostors();
-}
-
-//static
-void LLVOAvatar::resetImpostors()
-{
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* avatar = (LLVOAvatar*) *iter;
- avatar->mImpostor.release();
- }
-}
-
-// static
-void LLVOAvatar::deleteCachedImages(bool clearAll)
-{
- if (LLTexLayerSet::sHasCaches)
- {
- lldebugs << "Deleting layer set caches" << llendl;
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* inst = (LLVOAvatar*) *iter;
- inst->deleteLayerSetCaches(clearAll);
- }
- LLTexLayerSet::sHasCaches = FALSE;
- }
- LLVOAvatarSelf::deleteScratchTextures();
- LLTexLayerStaticImageList::getInstance()->deleteCachedImages();
-}
-
-
-//------------------------------------------------------------------------
-// static
-// LLVOAvatar::initClass()
-//------------------------------------------------------------------------
-void LLVOAvatar::initClass()
-{
- std::string xmlFile;
-
- xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
- BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
- if (!success)
- {
- llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl;
- }
-
- // now sanity check xml file
- LLXmlTreeNode* root = sXMLTree.getRoot();
- if (!root)
- {
- llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl;
- return;
- }
-
- //-------------------------------------------------------------------------
- // <linden_avatar version="1.0"> (root)
- //-------------------------------------------------------------------------
- if( !root->hasName( "linden_avatar" ) )
- {
- llerrs << "Invalid avatar file header: " << xmlFile << llendl;
- }
-
- std::string version;
- static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
- {
- llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl;
- }
-
- S32 wearable_def_version = 1;
- static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
- root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
- LLWearable::setCurrentDefinitionVersion( wearable_def_version );
-
- std::string mesh_file_name;
-
- LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
- if (!skeleton_node)
- {
- llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl;
- return;
- }
-
- std::string skeleton_file_name;
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
- {
- llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl;
- }
-
- std::string skeleton_path;
- skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
- if (!parseSkeletonFile(skeleton_path))
- {
- llerrs << "Error parsing skeleton file: " << skeleton_path << llendl;
- }
-
- // Process XML data
-
- // avatar_skeleton.xml
- llassert(!sAvatarSkeletonInfo);
- sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo;
- if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot()))
- {
- llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl;
- }
- // parse avatar_lad.xml
- llassert(!sAvatarXmlInfo);
- sAvatarXmlInfo = new LLVOAvatarXmlInfo;
- if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
- if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
- if (!sAvatarXmlInfo->parseXmlColorNodes(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
- if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
- if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
- if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
- {
- llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
- }
-
- gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise");
- gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot");
- gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION,"physics_motion");
- gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing");
- gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye");
- gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust");
- gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion");
- gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot");
- gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix");
- gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target");
- gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust");
-}
-
-
-void LLVOAvatar::cleanupClass()
-{
- deleteAndClear(sAvatarXmlInfo);
- sSkeletonXMLTree.cleanup();
- sXMLTree.cleanup();
-}
-
-void LLVOAvatar::initInstance(void)
-{
- //-------------------------------------------------------------------------
- // initialize joint, mesh and shape members
- //-------------------------------------------------------------------------
- mRoot.setName( "mRoot" );
-
- for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
- iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
- ++iter)
- {
- const EMeshIndex mesh_index = iter->first;
- const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second;
- LLViewerJoint* joint = new LLViewerJoint();
- joint->setName(mesh_dict->mName);
- joint->setMeshID(mesh_index);
- mMeshLOD.push_back(joint);
-
- /* mHairLOD.setName("mHairLOD");
- mHairMesh0.setName("mHairMesh0");
- mHairMesh0.setMeshID(MESH_ID_HAIR);
- mHairMesh1.setName("mHairMesh1"); */
- for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
- {
- LLViewerJointMesh* mesh = new LLViewerJointMesh();
- std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast<std::string>(lod);
- // We pre-pended an m - need to capitalize first character for camelCase
- mesh_name[1] = toupper(mesh_name[1]);
- mesh->setName(mesh_name);
- mesh->setMeshID(mesh_index);
- mesh->setPickName(mesh_dict->mPickName);
- mesh->setIsTransparent(FALSE);
- switch((int)mesh_index)
- {
- case MESH_ID_HAIR:
- mesh->setIsTransparent(TRUE);
- break;
- case MESH_ID_SKIRT:
- mesh->setIsTransparent(TRUE);
- break;
- case MESH_ID_EYEBALL_LEFT:
- case MESH_ID_EYEBALL_RIGHT:
- mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f );
- break;
- }
-
- joint->mMeshParts.push_back(mesh);
- }
- }
-
- //-------------------------------------------------------------------------
- // associate baked textures with meshes
- //-------------------------------------------------------------------------
- for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
- iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
- ++iter)
- {
- const EMeshIndex mesh_index = iter->first;
- const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second;
- const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID;
- // Skip it if there's no associated baked texture.
- if (baked_texture_index == BAKED_NUM_INDICES) continue;
-
- for (std::vector<LLViewerJointMesh* >::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin();
- iter != mMeshLOD[mesh_index]->mMeshParts.end();
- ++iter)
- {
- LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter;
- mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh);
- }
- }
-
-
- //-------------------------------------------------------------------------
- // register motions
- //-------------------------------------------------------------------------
- if (LLCharacter::sInstances.size() == 1)
- {
- LLKeyframeMotion::setVFS(gStaticVFS);
- registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create );
- registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create );
- registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create );
- registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create );
- registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create );
- registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create );
-
- // motions without a start/stop bit
- registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create );
- registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create );
- registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create );
- registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create );
- registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create );
- registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create );
- registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create );
- registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create );
- registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create );
- registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create );
- registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create );
- registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create );
- registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create );
-
- }
-
- if (gNoRender)
- {
- return;
- }
-
- buildCharacter();
-
- if (gNoRender)
- {
- return;
- }
-
- // preload specific motions here
- createMotion( ANIM_AGENT_CUSTOMIZE);
- createMotion( ANIM_AGENT_CUSTOMIZE_DONE);
-
- //VTPause(); // VTune
-
- mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
-
-}
-
-const LLVector3 LLVOAvatar::getRenderPosition() const
-{
- if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
- {
- return getPositionAgent();
- }
- else if (isRoot())
- {
- if ( !mHasPelvisOffset )
- {
- return mDrawable->getPositionAgent();
- }
- else
- {
- //Apply a pelvis fixup (as defined by the avs skin)
- LLVector3 pos = mDrawable->getPositionAgent();
- pos[VZ] += mPelvisFixup;
- return pos;
- }
- }
- else
- {
- return getPosition() * mDrawable->getParent()->getRenderMatrix();
- }
-}
-
-void LLVOAvatar::updateDrawable(BOOL force_damped)
-{
- clearChanged(SHIFTED);
-}
-
-void LLVOAvatar::onShift(const LLVector4a& shift_vector)
-{
- const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector);
- mLastAnimExtents[0] += shift;
- mLastAnimExtents[1] += shift;
- mNeedsImpostorUpdate = TRUE;
- mNeedsAnimUpdate = TRUE;
-}
-
-void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
-{
- if (isImpostor() && !needsImpostorUpdate())
- {
- LLVector3 delta = getRenderPosition() -
- ((LLVector3(mDrawable->getPositionGroup().getF32ptr())-mImpostorOffset));
-
- newMin.load3( (mLastAnimExtents[0] + delta).mV);
- newMax.load3( (mLastAnimExtents[1] + delta).mV);
- }
- else
- {
- getSpatialExtents(newMin,newMax);
- mLastAnimExtents[0].set(newMin.getF32ptr());
- mLastAnimExtents[1].set(newMax.getF32ptr());
- LLVector4a pos_group;
- pos_group.setAdd(newMin,newMax);
- pos_group.mul(0.5f);
- mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();
- mDrawable->setPositionGroup(pos_group);
- }
-}
-
-void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
-{
- LLVector4a buffer(0.25f);
- LLVector4a pos;
- pos.load3(getRenderPosition().mV);
- newMin.setSub(pos, buffer);
- newMax.setAdd(pos, buffer);
-
- float max_attachment_span = get_default_max_prim_scale() * 5.0f;
-
- //stretch bounding box by joint positions
- for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i)
- {
- LLPolyMesh* mesh = i->second;
- for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
- {
- LLVector4a trans;
- trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV);
- update_min_max(newMin, newMax, trans);
- }
- }
-
- LLVector4a center, size;
- center.setAdd(newMin, newMax);
- center.mul(0.5f);
-
- size.setSub(newMax,newMin);
- size.mul(0.5f);
-
- mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
-
- //stretch bounding box by attachments
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
-
- if (!attachment->getValid())
- {
- continue ;
- }
-
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isHUDAttachment())
- {
- LLDrawable* drawable = attached_object->mDrawable;
- if (drawable && !drawable->isState(LLDrawable::RIGGED))
- {
- LLSpatialBridge* bridge = drawable->getSpatialBridge();
- if (bridge)
- {
- const LLVector4a* ext = bridge->getSpatialExtents();
- LLVector4a distance;
- distance.setSub(ext[1], ext[0]);
- LLVector4a max_span(max_attachment_span);
-
- S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7;
-
- // Only add the prim to spatial extents calculations if it isn't a megaprim.
- // max_attachment_span calculated at the start of the function
- // (currently 5 times our max prim size)
- if (lt == 0x7)
- {
- update_min_max(newMin,newMax,ext[0]);
- update_min_max(newMin,newMax,ext[1]);
- }
- }
- }
- }
- }
- }
-
- //pad bounding box
-
- newMin.sub(buffer);
- newMax.add(buffer);
-}
-
-//-----------------------------------------------------------------------------
-// renderCollisionVolumes()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::renderCollisionVolumes()
-{
- for (S32 i = 0; i < mNumCollisionVolumes; i++)
- {
- mCollisionVolumes[i].renderCollision();
- }
-
- if (mNameText.notNull())
- {
- LLVector3 unused;
- mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE);
- }
-}
-
-BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
- S32 face,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection,
- LLVector2* tex_coord,
- LLVector3* normal,
- LLVector3* bi_normal)
-{
- if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar)
- {
- return FALSE;
- }
-
- if (lineSegmentBoundingBox(start, end))
- {
- for (S32 i = 0; i < mNumCollisionVolumes; ++i)
- {
- mCollisionVolumes[i].updateWorldMatrix();
-
- glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix);
- glh::matrix4f inverse = mat.inverse();
- glh::matrix4f norm_mat = inverse.transpose();
-
- glh::vec3f p1(start.mV);
- glh::vec3f p2(end.mV);
-
- inverse.mult_matrix_vec(p1);
- inverse.mult_matrix_vec(p2);
-
- LLVector3 position;
- LLVector3 norm;
-
- if (linesegment_sphere(LLVector3(p1.v), LLVector3(p2.v), LLVector3(0,0,0), 1.f, position, norm))
- {
- glh::vec3f res_pos(position.mV);
- mat.mult_matrix_vec(res_pos);
-
- norm.normalize();
- glh::vec3f res_norm(norm.mV);
- norm_mat.mult_matrix_dir(res_norm);
-
- if (intersection)
- {
- *intersection = LLVector3(res_pos.v);
- }
-
- if (normal)
- {
- *normal = LLVector3(res_norm.v);
- }
-
- return TRUE;
- }
- }
- }
-
- LLVector3 position;
- if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position))
- {
- if (intersection)
- {
- *intersection = position;
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// parseSkeletonFile()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- //-------------------------------------------------------------------------
- // parse the file
- //-------------------------------------------------------------------------
- BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE );
-
- if (!parsesuccess)
- {
- llerrs << "Can't parse skeleton file: " << filename << llendl;
- return FALSE;
- }
-
- // now sanity check xml file
- LLXmlTreeNode* root = sSkeletonXMLTree.getRoot();
- if (!root)
- {
- llerrs << "No root node found in avatar skeleton file: " << filename << llendl;
- return FALSE;
- }
-
- if( !root->hasName( "linden_skeleton" ) )
- {
- llerrs << "Invalid avatar skeleton file header: " << filename << llendl;
- return FALSE;
- }
-
- std::string version;
- static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
- {
- llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl;
- return FALSE;
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// setupBone()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &volume_num, S32 &joint_num)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- LLViewerJoint* joint = NULL;
-
- if (info->mIsJoint)
- {
- joint = (LLViewerJoint*)getCharacterJoint(joint_num);
- if (!joint)
- {
- llwarns << "Too many bones" << llendl;
- return FALSE;
- }
- joint->setName( info->mName );
- }
- else // collision volume
- {
- if (volume_num >= (S32)mNumCollisionVolumes)
- {
- llwarns << "Too many bones" << llendl;
- return FALSE;
- }
- joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]);
- joint->setName( info->mName );
- }
-
- // add to parent
- if (parent)
- {
- parent->addChild( joint );
- }
-
- joint->setPosition(info->mPos);
- joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
- info->mRot.mV[VZ], LLQuaternion::XYZ));
- joint->setScale(info->mScale);
-
- joint->setDefaultFromCurrentXform();
-
- if (info->mIsJoint)
- {
- joint->setSkinOffset( info->mPivot );
- joint_num++;
- }
- else // collision volume
- {
- volume_num++;
- }
-
- // setup children
- LLVOAvatarBoneInfo::child_list_t::const_iterator iter;
- for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
- {
- LLVOAvatarBoneInfo *child_info = *iter;
- if (!setupBone(child_info, joint, volume_num, joint_num))
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// buildSkeleton()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- //-------------------------------------------------------------------------
- // allocate joints
- //-------------------------------------------------------------------------
- if (!allocateCharacterJoints(info->mNumBones))
- {
- llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl;
- return FALSE;
- }
-
- //-------------------------------------------------------------------------
- // allocate volumes
- //-------------------------------------------------------------------------
- if (info->mNumCollisionVolumes)
- {
- if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
- {
- llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl;
- return FALSE;
- }
- }
-
- S32 current_joint_num = 0;
- S32 current_volume_num = 0;
- LLVOAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
- for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
- {
- LLVOAvatarBoneInfo *info = *iter;
- if (!setupBone(info, NULL, current_volume_num, current_joint_num))
- {
- llerrs << "Error parsing bone in skeleton file" << llendl;
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-LLVOAvatar* LLVOAvatar::asAvatar()
-{
- return this;
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::startDefaultMotions()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::startDefaultMotions()
-{
- //-------------------------------------------------------------------------
- // start default motions
- //-------------------------------------------------------------------------
- startMotion( ANIM_AGENT_HEAD_ROT );
- startMotion( ANIM_AGENT_EYE );
- startMotion( ANIM_AGENT_BODY_NOISE );
- startMotion( ANIM_AGENT_BREATHE_ROT );
- startMotion( ANIM_AGENT_PHYSICS_MOTION );
- startMotion( ANIM_AGENT_HAND_MOTION );
- startMotion( ANIM_AGENT_PELVIS_FIX );
-
- //-------------------------------------------------------------------------
- // restart any currently active motions
- //-------------------------------------------------------------------------
- processAnimationStateChanges();
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::buildCharacter()
-// Deferred initialization and rebuild of the avatar.
-//-----------------------------------------------------------------------------
-void LLVOAvatar::buildCharacter()
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- //-------------------------------------------------------------------------
- // remove all references to our existing skeleton
- // so we can rebuild it
- //-------------------------------------------------------------------------
- flushAllMotions();
-
- //-------------------------------------------------------------------------
- // remove all of mRoot's children
- //-------------------------------------------------------------------------
- mRoot.removeAllChildren();
- mIsBuilt = FALSE;
-
- //-------------------------------------------------------------------------
- // clear mesh data
- //-------------------------------------------------------------------------
- for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
- jointIter != mMeshLOD.end(); ++jointIter)
- {
- LLViewerJoint* joint = (LLViewerJoint*) *jointIter;
- for (std::vector<LLViewerJointMesh*>::iterator meshIter = joint->mMeshParts.begin();
- meshIter != joint->mMeshParts.end(); ++meshIter)
- {
- LLViewerJointMesh * mesh = (LLViewerJointMesh *) *meshIter;
- mesh->setMesh(NULL);
- }
- }
-
- //-------------------------------------------------------------------------
- // (re)load our skeleton and meshes
- //-------------------------------------------------------------------------
- LLTimer timer;
-
- BOOL status = loadAvatar();
- stop_glerror();
-
- if (gNoRender)
- {
- // Still want to load the avatar skeleton so visual parameters work.
- return;
- }
-
-// gPrintMessagesThisFrame = TRUE;
- lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl;
-
- if (!status)
- {
- if (isSelf())
- {
- llerrs << "Unable to load user's avatar" << llendl;
- }
- else
- {
- llwarns << "Unable to load other's avatar" << llendl;
- }
- return;
- }
-
- //-------------------------------------------------------------------------
- // initialize "well known" joint pointers
- //-------------------------------------------------------------------------
- mPelvisp = (LLViewerJoint*)mRoot.findJoint("mPelvis");
- mTorsop = (LLViewerJoint*)mRoot.findJoint("mTorso");
- mChestp = (LLViewerJoint*)mRoot.findJoint("mChest");
- mNeckp = (LLViewerJoint*)mRoot.findJoint("mNeck");
- mHeadp = (LLViewerJoint*)mRoot.findJoint("mHead");
- mSkullp = (LLViewerJoint*)mRoot.findJoint("mSkull");
- mHipLeftp = (LLViewerJoint*)mRoot.findJoint("mHipLeft");
- mHipRightp = (LLViewerJoint*)mRoot.findJoint("mHipRight");
- mKneeLeftp = (LLViewerJoint*)mRoot.findJoint("mKneeLeft");
- mKneeRightp = (LLViewerJoint*)mRoot.findJoint("mKneeRight");
- mAnkleLeftp = (LLViewerJoint*)mRoot.findJoint("mAnkleLeft");
- mAnkleRightp = (LLViewerJoint*)mRoot.findJoint("mAnkleRight");
- mFootLeftp = (LLViewerJoint*)mRoot.findJoint("mFootLeft");
- mFootRightp = (LLViewerJoint*)mRoot.findJoint("mFootRight");
- mWristLeftp = (LLViewerJoint*)mRoot.findJoint("mWristLeft");
- mWristRightp = (LLViewerJoint*)mRoot.findJoint("mWristRight");
- mEyeLeftp = (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
- mEyeRightp = (LLViewerJoint*)mRoot.findJoint("mEyeRight");
-
- //-------------------------------------------------------------------------
- // Make sure "well known" pointers exist
- //-------------------------------------------------------------------------
- if (!(mPelvisp &&
- mTorsop &&
- mChestp &&
- mNeckp &&
- mHeadp &&
- mSkullp &&
- mHipLeftp &&
- mHipRightp &&
- mKneeLeftp &&
- mKneeRightp &&
- mAnkleLeftp &&
- mAnkleRightp &&
- mFootLeftp &&
- mFootRightp &&
- mWristLeftp &&
- mWristRightp &&
- mEyeLeftp &&
- mEyeRightp))
- {
- llerrs << "Failed to create avatar." << llendl;
- return;
- }
-
- //-------------------------------------------------------------------------
- // initialize the pelvis
- //-------------------------------------------------------------------------
- mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
-
- //-------------------------------------------------------------------------
- // set head offset from pelvis
- //-------------------------------------------------------------------------
- updateHeadOffset();
-
- //-------------------------------------------------------------------------
- // initialize lip sync morph pointers
- //-------------------------------------------------------------------------
- mOohMorph = getVisualParam( "Lipsync_Ooh" );
- mAahMorph = getVisualParam( "Lipsync_Aah" );
-
- // If we don't have the Ooh morph, use the Kiss morph
- if (!mOohMorph)
- {
- llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl;
- mOohMorph = getVisualParam( "Express_Kiss" );
- }
-
- // If we don't have the Aah morph, use the Open Mouth morph
- if (!mAahMorph)
- {
- llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl;
- mAahMorph = getVisualParam( "Express_Open_Mouth" );
- }
-
- startDefaultMotions();
-
- //-------------------------------------------------------------------------
- // restart any currently active motions
- //-------------------------------------------------------------------------
- processAnimationStateChanges();
-
- mIsBuilt = TRUE;
- stop_glerror();
-
- mMeshValid = TRUE;
-}
-
-
-//-----------------------------------------------------------------------------
-// releaseMeshData()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::releaseMeshData()
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy)
- {
- return;
- }
-
- //llinfos << "Releasing" << llendl;
-
- // cleanup mesh data
- for (std::vector<LLViewerJoint*>::iterator iter = mMeshLOD.begin();
- iter != mMeshLOD.end();
- ++iter)
- {
- LLViewerJoint* joint = (LLViewerJoint*) *iter;
- joint->setValid(FALSE, TRUE);
- }
-
- //cleanup data
- if (mDrawable.notNull())
- {
- LLFace* facep = mDrawable->getFace(0);
- facep->setSize(0, 0);
- for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
- {
- facep = mDrawable->getFace(i);
- facep->setSize(0, 0);
- }
- }
-
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (!attachment->getIsHUDAttachment())
- {
- attachment->setAttachmentVisibility(FALSE);
- }
- }
- mMeshValid = FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// restoreMeshData()
-//-----------------------------------------------------------------------------
-// virtual
-void LLVOAvatar::restoreMeshData()
-{
- llassert(!isSelf());
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- //llinfos << "Restoring" << llendl;
- mMeshValid = TRUE;
- updateJointLODs();
-
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (!attachment->getIsHUDAttachment())
- {
- attachment->setAttachmentVisibility(TRUE);
- }
- }
-
- // force mesh update as LOD might not have changed to trigger this
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
-}
-
-//-----------------------------------------------------------------------------
-// updateMeshData()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateMeshData()
-{
- if (mDrawable.notNull())
- {
- stop_glerror();
-
- S32 f_num = 0 ;
- const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer.
- const S32 num_parts = mMeshLOD.size();
-
- // this order is determined by number of LODS
- // if a mesh earlier in this list changed LODs while a later mesh doesn't,
- // the later mesh's index offset will be inaccurate
- for(S32 part_index = 0 ; part_index < num_parts ;)
- {
- S32 j = part_index ;
- U32 last_v_num = 0, num_vertices = 0 ;
- U32 last_i_num = 0, num_indices = 0 ;
-
- while(part_index < num_parts && num_vertices < VERTEX_NUMBER_THRESHOLD)
- {
- last_v_num = num_vertices ;
- last_i_num = num_indices ;
-
- mMeshLOD[part_index++]->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea);
- }
- if(num_vertices < 1)//skip empty meshes
- {
- continue ;
- }
- if(last_v_num > 0)//put the last inserted part into next vertex buffer.
- {
- num_vertices = last_v_num ;
- num_indices = last_i_num ;
- part_index-- ;
- }
-
- LLFace* facep ;
- if(f_num < mDrawable->getNumFaces())
- {
- facep = mDrawable->getFace(f_num);
- }
- else
- {
- facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ;
- }
-
- // resize immediately
- facep->setSize(num_vertices, num_indices);
-
- bool terse_update = false;
-
- facep->setGeomIndex(0);
- facep->setIndicesIndex(0);
-
- LLVertexBuffer* buff = facep->getVertexBuffer();
- if(!facep->getVertexBuffer())
- {
- buff = new LLVertexBufferAvatar();
- buff->allocateBuffer(num_vertices, num_indices, TRUE);
- facep->setVertexBuffer(buff);
- }
- else
- {
- if (buff->getRequestedIndices() == num_indices &&
- buff->getRequestedVerts() == num_vertices)
- {
- terse_update = true;
- }
- else
- {
- buff->resizeBuffer(num_vertices, num_indices);
- }
- }
-
-
- // This is a hack! Avatars have their own pool, so we are detecting
- // the case of more than one avatar in the pool (thus > 0 instead of >= 0)
- if (facep->getGeomIndex() > 0)
- {
- llerrs << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << llendl;
- }
-
- for(S32 k = j ; k < part_index ; k++)
- {
- mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update);
- }
-
- stop_glerror();
- buff->setBuffer(0);
-
- if(!f_num)
- {
- f_num += mNumInitFaces ;
- }
- else
- {
- f_num++ ;
- }
- }
- }
-}
-
-//------------------------------------------------------------------------
-
-//------------------------------------------------------------------------
-// The viewer can only suggest a good size for the agent,
-// the simulator will keep it inside a reasonable range.
-void LLVOAvatar::computeBodySize()
-{
- LLVector3 pelvis_scale = mPelvisp->getScale();
-
- // some of the joints have not been cached
- LLVector3 skull = mSkullp->getPosition();
- LLVector3 skull_scale = mSkullp->getScale();
-
- LLVector3 neck = mNeckp->getPosition();
- LLVector3 neck_scale = mNeckp->getScale();
-
- LLVector3 chest = mChestp->getPosition();
- LLVector3 chest_scale = mChestp->getScale();
-
- // the rest of the joints have been cached
- LLVector3 head = mHeadp->getPosition();
- LLVector3 head_scale = mHeadp->getScale();
-
- LLVector3 torso = mTorsop->getPosition();
- LLVector3 torso_scale = mTorsop->getScale();
-
- LLVector3 hip = mHipLeftp->getPosition();
- LLVector3 hip_scale = mHipLeftp->getScale();
-
- LLVector3 knee = mKneeLeftp->getPosition();
- LLVector3 knee_scale = mKneeLeftp->getScale();
-
- LLVector3 ankle = mAnkleLeftp->getPosition();
- LLVector3 ankle_scale = mAnkleLeftp->getScale();
-
- LLVector3 foot = mFootLeftp->getPosition();
-
- mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
- knee.mV[VZ] * hip_scale.mV[VZ] -
- ankle.mV[VZ] * knee_scale.mV[VZ] -
- foot.mV[VZ] * ankle_scale.mV[VZ];
-
- LLVector3 new_body_size;
- new_body_size.mV[VZ] = mPelvisToFoot +
- // the sqrt(2) correction below is an approximate
- // correction to get to the top of the head
- F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
- head.mV[VZ] * neck_scale.mV[VZ] +
- neck.mV[VZ] * chest_scale.mV[VZ] +
- chest.mV[VZ] * torso_scale.mV[VZ] +
- torso.mV[VZ] * pelvis_scale.mV[VZ];
-
- // TODO -- measure the real depth and width
- new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
- new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
-
- if (new_body_size != mBodySize)
- {
- mBodySize = new_body_size;
-
- if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
- { // notify simulator of change in size
- // but not if we are in the middle of updating appearance
- gAgent.sendAgentSetAppearance();
- }
- }
-}
-
-//------------------------------------------------------------------------
-// LLVOAvatar::processUpdateMessage()
-//------------------------------------------------------------------------
-U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num, const EObjectUpdateType update_type,
- LLDataPacker *dp)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- LLVector3 old_vel = getVelocity();
- const BOOL has_name = !getNVPair("FirstName");
-
- // Do base class updates...
- U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
-
- // Print out arrival information once we have name of avatar.
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- if (has_name && getNVPair("FirstName"))
- {
- mDebugExistenceTimer.reset();
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezArrivedNotification",args);
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl;
- }
- }
- if(retval & LLViewerObject::INVALID_UPDATE)
- {
- if (isSelf())
- {
- //tell sim to cancel this update
- gAgent.teleportViaLocation(gAgent.getPositionGlobal());
- }
- }
-
- //llinfos << getRotation() << llendl;
- //llinfos << getPosition() << llendl;
-
- return retval;
-}
-
-// virtual
-S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
-{
- // The core setTETexture() method requests images, so we need
- // to redirect certain avatar texture requests to different sims.
- if (isIndexBakedTexture((ETextureIndex)te))
- {
- LLHost target_host = getObjectHost();
- return setTETextureCore(te, uuid, target_host);
- }
- else
- {
- return setTETextureCore(te, uuid, LLHost::invalid);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar");
-static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints");
-
-//------------------------------------------------------------------------
-// LLVOAvatar::dumpAnimationState()
-//------------------------------------------------------------------------
-void LLVOAvatar::dumpAnimationState()
-{
- llinfos << "==============================================" << llendl;
- for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it)
- {
- LLUUID id = it->first;
- std::string playtag = "";
- if (mPlayingAnimations.find(id) != mPlayingAnimations.end())
- {
- playtag = "*";
- }
- llinfos << gAnimLibrary.animationName(id) << playtag << llendl;
- }
- for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it)
- {
- LLUUID id = it->first;
- bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end();
- if (!is_signaled)
- {
- llinfos << gAnimLibrary.animationName(id) << "!S" << llendl;
- }
- }
-}
-
-//------------------------------------------------------------------------
-// idleUpdate()
-//------------------------------------------------------------------------
-BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
- LLFastTimer t(FTM_AVATAR_UPDATE);
-
- if (isDead())
- {
- llinfos << "Warning! Idle on dead avatar" << llendl;
- return TRUE;
- }
-
- if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
- {
- return TRUE;
- }
-
- checkTextureLoading() ;
-
- // force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
- setPixelAreaAndAngle(gAgent);
-
- // force asynchronous drawable update
- if(mDrawable.notNull() && !gNoRender)
- {
- LLFastTimer t(FTM_JOINT_UPDATE);
-
- if (mIsSitting && getParent())
- {
- LLViewerObject *root_object = (LLViewerObject*)getRoot();
- LLDrawable* drawablep = root_object->mDrawable;
- // if this object hasn't already been updated by another avatar...
- if (drawablep) // && !drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- if (root_object->isSelected())
- {
- gPipeline.updateMoveNormalAsync(drawablep);
- }
- else
- {
- gPipeline.updateMoveDampedAsync(drawablep);
- }
- }
- }
- else
- {
- gPipeline.updateMoveDampedAsync(mDrawable);
- }
- }
-
- //--------------------------------------------------------------------
- // set alpha flag depending on state
- //--------------------------------------------------------------------
-
- if (isSelf())
- {
- LLViewerObject::idleUpdate(agent, world, time);
-
- // trigger fidget anims
- if (isAnyAnimationSignaled(AGENT_STAND_ANIMS, NUM_AGENT_STAND_ANIMS))
- {
- agent.fidget();
- }
- }
- else
- {
- // Should override the idleUpdate stuff and leave out the angular update part.
- LLQuaternion rotation = getRotation();
- LLViewerObject::idleUpdate(agent, world, time);
- setRotation(rotation);
- }
-
- // attach objects that were waiting for a drawable
- lazyAttach();
-
- // animate the character
- // store off last frame's root position to be consistent with camera position
- LLVector3 root_pos_last = mRoot.getWorldPosition();
- BOOL detailed_update = updateCharacter(agent);
-
- if (gNoRender)
- {
- return TRUE;
- }
-
- static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
- bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) &&
- LLVoiceClient::getInstance()->getVoiceEnabled(mID);
-
- idleUpdateVoiceVisualizer( voice_enabled );
- idleUpdateMisc( detailed_update );
- idleUpdateAppearanceAnimation();
- if (detailed_update)
- {
- idleUpdateLipSync( voice_enabled );
- idleUpdateLoadingEffect();
- idleUpdateBelowWater(); // wind effect uses this
- idleUpdateWindEffect();
- }
-
- idleUpdateNameTag( root_pos_last );
- idleUpdateRenderCost();
-
- return TRUE;
-}
-
-void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
-{
- bool render_visualizer = voice_enabled;
-
- // Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
- if(isSelf())
- {
- if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic"))
- {
- render_visualizer = false;
- }
- }
-
- mVoiceVisualizer->setVoiceEnabled(render_visualizer);
-
- if ( voice_enabled )
- {
- //----------------------------------------------------------------
- // Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
- //----------------------------------------------------------------
- if( isSelf() )
- {
- //----------------------------------------------------------------------------------------
- // The following takes the voice signal and uses that to trigger gesticulations.
- //----------------------------------------------------------------------------------------
- int lastGesticulationLevel = mCurrentGesticulationLevel;
- mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel();
-
- //---------------------------------------------------------------------------------------------------
- // If "current gesticulation level" changes, we catch this, and trigger the new gesture
- //---------------------------------------------------------------------------------------------------
- if ( lastGesticulationLevel != mCurrentGesticulationLevel )
- {
- if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF )
- {
- std::string gestureString = "unInitialized";
- if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; }
- else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; }
- else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; }
- else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; }
-
- // this is the call that Karl S. created for triggering gestures from within the code.
- LLGestureMgr::instance().triggerAndReviseString( gestureString );
- }
- }
-
- } //if( isSelf() )
-
- //-----------------------------------------------------------------------------------------------------------------
- // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer.
- // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol.
- //
- // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
- // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.
- //-----------------------------------------------------------------------------------------------------------------
- if (LLVoiceClient::getInstance()->getIsSpeaking( mID ))
- {
- if (!mVoiceVisualizer->getCurrentlySpeaking())
- {
- mVoiceVisualizer->setStartSpeaking();
-
- //printf( "gAwayTimer.reset();\n" );
- }
-
- mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) );
-
- if( isSelf() )
- {
- gAgent.clearAFK();
- }
- }
- else
- {
- if ( mVoiceVisualizer->getCurrentlySpeaking() )
- {
- mVoiceVisualizer->setStopSpeaking();
-
- if ( mLipSyncActive )
- {
- if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE);
- if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE);
-
- mLipSyncActive = false;
- LLCharacter::updateVisualParams();
- dirtyMesh();
- }
- }
- }
-
- //--------------------------------------------------------------------------------------------
- // here we get the approximate head position and set as sound source for the voice symbol
- // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
- //--------------------------------------------------------------------------------------------
-
- if ( mIsSitting )
- {
- LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
- mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
- }
- else
- {
- LLVector3 tagPos = mRoot.getWorldPosition();
- tagPos[VZ] -= mPelvisToFoot;
- tagPos[VZ] += ( mBodySize[VZ] + 0.125f );
- mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );
- }
- }//if ( voiceEnabled )
-}
-
-static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments");
-
-void LLVOAvatar::idleUpdateMisc(bool detailed_update)
-{
- if (LLVOAvatar::sJointDebug)
- {
- llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl;
- }
-
- LLJoint::sNumUpdates = 0;
- LLJoint::sNumTouches = 0;
-
- BOOL visible = isVisible() || mNeedsAnimUpdate;
-
- // update attachments positions
- if (detailed_update || !sUseImpostors)
- {
- LLFastTimer t(FTM_ATTACHMENT_UPDATE);
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
-
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject* attached_object = (*attachment_iter);
- BOOL visibleAttachment = visible || (attached_object &&
- !(attached_object->mDrawable->getSpatialBridge() &&
- attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
-
- if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
- {
- // if selecting any attachments, update all of them as non-damped
- if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
- {
- gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
- }
- else
- {
- gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
- }
-
- LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
- if (bridge)
- {
- gPipeline.updateMoveNormalAsync(bridge);
- }
- attached_object->updateText();
- }
- }
- }
- }
-
- mNeedsAnimUpdate = FALSE;
-
- if (isImpostor() && !mNeedsImpostorUpdate)
- {
- LLVector4a ext[2];
- F32 distance;
- LLVector3 angle;
-
- getImpostorValues(ext, angle, distance);
-
- for (U32 i = 0; i < 3 && !mNeedsImpostorUpdate; i++)
- {
- F32 cur_angle = angle.mV[i];
- F32 old_angle = mImpostorAngle.mV[i];
- F32 angle_diff = fabsf(cur_angle-old_angle);
-
- if (angle_diff > F_PI/512.f*distance*mUpdatePeriod)
- {
- mNeedsImpostorUpdate = TRUE;
- }
- }
-
- if (detailed_update && !mNeedsImpostorUpdate)
- { //update impostor if view angle, distance, or bounding box change
- //significantly
-
- F32 dist_diff = fabsf(distance-mImpostorDistance);
- if (dist_diff/mImpostorDistance > 0.1f)
- {
- mNeedsImpostorUpdate = TRUE;
- }
- else
- {
- //VECTORIZE THIS
- getSpatialExtents(ext[0], ext[1]);
- LLVector4a diff;
- diff.setSub(ext[1], mImpostorExtents[1]);
- if (diff.getLength3().getF32() > 0.05f)
- {
- mNeedsImpostorUpdate = TRUE;
- }
- else
- {
- diff.setSub(ext[0], mImpostorExtents[0]);
- if (diff.getLength3().getF32() > 0.05f)
- {
- mNeedsImpostorUpdate = TRUE;
- }
- }
- }
- }
- }
-
- mDrawable->movePartition();
-
- //force a move if sitting on an active object
- if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
- {
- gPipeline.markMoved(mDrawable, TRUE);
- }
-}
-
-void LLVOAvatar::idleUpdateAppearanceAnimation()
-{
- // update morphing params
- if (mAppearanceAnimating)
- {
- ESex avatar_sex = getSex();
- F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32();
- if (appearance_anim_time >= APPEARANCE_MORPH_TIME)
- {
- mAppearanceAnimating = FALSE;
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->isTweakable())
- {
- param->stopAnimating(FALSE);
- }
- }
- updateVisualParams();
- if (isSelf())
- {
- gAgent.sendAgentSetAppearance();
- }
- }
- else
- {
- F32 morph_amt = calcMorphAmount();
- LLVisualParam *param;
-
- if (!isSelf())
- {
- // animate only top level params for non-self avatars
- for (param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->isTweakable())
- {
- param->animate(morph_amt, FALSE);
- }
- }
- }
-
- // apply all params
- for (param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- param->apply(avatar_sex);
- }
-
- mLastAppearanceBlendTime = appearance_anim_time;
- }
- dirtyMesh();
- }
-}
-
-F32 LLVOAvatar::calcMorphAmount()
-{
- F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32();
- F32 blend_frac = calc_bouncy_animation(appearance_anim_time / APPEARANCE_MORPH_TIME);
- F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / APPEARANCE_MORPH_TIME);
-
- F32 morph_amt;
- if (last_blend_frac == 1.f)
- {
- morph_amt = 1.f;
- }
- else
- {
- morph_amt = (blend_frac - last_blend_frac) / (1.f - last_blend_frac);
- }
-
- return morph_amt;
-}
-
-void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
-{
- // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
- if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) )
- {
- F32 ooh_morph_amount = 0.0f;
- F32 aah_morph_amount = 0.0f;
-
- mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount );
-
- if( mOohMorph )
- {
- F32 ooh_weight = mOohMorph->getMinWeight()
- + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight());
-
- mOohMorph->setWeight( ooh_weight, FALSE );
- }
-
- if( mAahMorph )
- {
- F32 aah_weight = mAahMorph->getMinWeight()
- + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight());
-
- mAahMorph->setWeight( aah_weight, FALSE );
- }
-
- mLipSyncActive = true;
- LLCharacter::updateVisualParams();
- dirtyMesh();
- }
-}
-
-void LLVOAvatar::idleUpdateLoadingEffect()
-{
- // update visibility when avatar is partially loaded
- if (updateIsFullyLoaded()) // changed?
- {
- if (isFullyLoaded() && isSelf())
- {
- static bool first_fully_visible = true;
- if (first_fully_visible)
- {
- llinfos << "self isFullyLoaded, first_fully_visible" << llendl;
-
- first_fully_visible = false;
- LLAppearanceMgr::instance().onFirstFullyVisible();
- }
- }
- if (isFullyLoaded())
- {
- deleteParticleSource();
- updateLOD();
- }
- else
- {
- LLPartSysData particle_parameters;
-
- // fancy particle cloud designed by Brent
- particle_parameters.mPartData.mMaxAge = 4.f;
- particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
- particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
- particle_parameters.mPartData.mStartScale.mV[VY] = 1.0f;
- particle_parameters.mPartData.mEndScale.mV[VX] = 0.02f;
- particle_parameters.mPartData.mEndScale.mV[VY] = 0.02f;
- particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f);
- particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f);
- particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
- LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
- particle_parameters.mPartImageID = cloud->getID();
- particle_parameters.mMaxAge = 0.f;
- particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;
- particle_parameters.mInnerAngle = F_PI;
- particle_parameters.mOuterAngle = 0.f;
- particle_parameters.mBurstRate = 0.02f;
- particle_parameters.mBurstRadius = 0.0f;
- particle_parameters.mBurstPartCount = 1;
- particle_parameters.mBurstSpeedMin = 0.1f;
- particle_parameters.mBurstSpeedMax = 1.f;
- particle_parameters.mPartData.mFlags = ( LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
- LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |
- LLPartData::LL_PART_TARGET_POS_MASK );
-
- setParticleSource(particle_parameters, getID());
- }
- }
-}
-
-void LLVOAvatar::idleUpdateWindEffect()
-{
- // update wind effect
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH))
- {
- F32 hover_strength = 0.f;
- F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast;
- mRippleTimeLast = mRippleTimer.getElapsedTimeF32();
- LLVector3 velocity = getVelocity();
- F32 speed = velocity.length();
- //RN: velocity varies too much frame to frame for this to work
- mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLCriticalDamp::getInterpolant(0.02f));
- mLastVel = velocity;
- LLVector4 wind;
- wind.setVec(getRegion()->mWind.getVelocityNoisy(getPositionAgent(), 4.f) - velocity);
-
- if (mInAir)
- {
- hover_strength = HOVER_EFFECT_STRENGTH * llmax(0.f, HOVER_EFFECT_MAX_SPEED - speed);
- }
-
- if (mBelowWater)
- {
- // TODO: make cloth flow more gracefully when underwater
- hover_strength += UNDERWATER_EFFECT_STRENGTH;
- }
-
- wind.mV[VZ] += hover_strength;
- wind.normalize();
-
- wind.mV[VW] = llmin(0.025f + (speed * 0.015f) + hover_strength, 0.5f);
- F32 interp;
- if (wind.mV[VW] > mWindVec.mV[VW])
- {
- interp = LLCriticalDamp::getInterpolant(0.2f);
- }
- else
- {
- interp = LLCriticalDamp::getInterpolant(0.4f);
- }
- mWindVec = lerp(mWindVec, wind, interp);
-
- F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f);
- mWindFreq = lerp(mWindFreq, wind_freq, interp);
-
- if (mBelowWater)
- {
- mWindFreq *= UNDERWATER_FREQUENCY_DAMP;
- }
-
- mRipplePhase += (time_delta * mWindFreq);
- if (mRipplePhase > F_TWO_PI)
- {
- mRipplePhase = fmodf(mRipplePhase, F_TWO_PI);
- }
- }
-}
-
-void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
-{
- // update chat bubble
- //--------------------------------------------------------------------
- // draw text label over character's head
- //--------------------------------------------------------------------
- if (mChatTimer.getElapsedTimeF32() > BUBBLE_CHAT_TIME)
- {
- mChats.clear();
- }
-
- const F32 time_visible = mTimeVisible.getElapsedTimeF32();
- const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds
- const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
- BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
- BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
- BOOL render_name = visible_chat ||
- (visible_avatar &&
- ((sRenderName == RENDER_NAME_ALWAYS) ||
- (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
- // If it's your own avatar, don't draw in mouselook, and don't
- // draw if we're specifically hiding our own name.
- if (isSelf())
- {
- render_name = render_name
- && !gAgentCamera.cameraMouselook()
- && (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf")
- && gSavedSettings.getS32("AvatarNameTagMode") ));
- }
-
- if ( !render_name )
- {
- if (mNameText)
- {
- // ...clean up old name tag
- mNameText->markDead();
- mNameText = NULL;
- sNumVisibleChatBubbles--;
- }
- return;
- }
-
- BOOL new_name = FALSE;
- if (visible_chat != mVisibleChat)
- {
- mVisibleChat = visible_chat;
- new_name = TRUE;
- }
-
- if (sRenderGroupTitles != mRenderGroupTitles)
- {
- mRenderGroupTitles = sRenderGroupTitles;
- new_name = TRUE;
- }
-
- // First Calculate Alpha
- // If alpha > 0, create mNameText if necessary, otherwise delete it
- F32 alpha = 0.f;
- if (mAppAngle > 5.f)
- {
- const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION;
- if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME)
- {
- alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION;
- }
- else
- {
- // ...not fading, full alpha
- alpha = 1.f;
- }
- }
- else if (mAppAngle > 2.f)
- {
- // far away is faded out also
- alpha = (mAppAngle-2.f)/3.f;
- }
-
- if (alpha <= 0.f)
- {
- if (mNameText)
- {
- mNameText->markDead();
- mNameText = NULL;
- sNumVisibleChatBubbles--;
- }
- return;
- }
-
- if (!mNameText)
- {
- mNameText = static_cast<LLHUDNameTag*>( LLHUDObject::addHUDObject(
- LLHUDObject::LL_HUD_NAME_TAG) );
- //mNameText->setMass(10.f);
- mNameText->setSourceObject(this);
- mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP);
- mNameText->setVisibleOffScreen(TRUE);
- mNameText->setMaxLines(11);
- mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
- sNumVisibleChatBubbles++;
- new_name = TRUE;
- }
-
- LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last);
- mNameText->setPositionAgent(name_position);
- idleUpdateNameTagText(new_name);
- idleUpdateNameTagAlpha(new_name, alpha);
-}
-
-void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
- {
- LLNameValue *title = getNVPair("Title");
- LLNameValue* firstname = getNVPair("FirstName");
- LLNameValue* lastname = getNVPair("LastName");
-
- // Avatars must have a first and last name
- if (!firstname || !lastname) return;
-
- bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end();
- bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end();
- bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end();
- bool is_muted;
- if (isSelf())
- {
- is_muted = false;
- }
- else
- {
- is_muted = LLMuteList::getInstance()->isMuted(getID());
- }
- bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
- bool is_cloud = getIsCloud();
-
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- if (is_appearance != mNameAppearance)
- {
- if (is_appearance)
- {
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args);
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl;
- }
- else
- {
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args);
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl;
- }
- }
- }
-
- // Rebuild name tag if state change detected
- if (mNameString.empty()
- || new_name
- || (!title && !mTitle.empty())
- || (title && mTitle != title->getString())
- || is_away != mNameAway
- || is_busy != mNameBusy
- || is_muted != mNameMute
- || is_appearance != mNameAppearance
- || is_friend != mNameFriend
- || is_cloud != mNameCloud)
- {
- LLColor4 name_tag_color = getNameTagColor(is_friend);
-
- clearNameTag();
-
- if (is_away || is_muted || is_busy || is_appearance)
- {
- std::string line;
- if (is_away)
- {
- line += LLTrans::getString("AvatarAway");
- line += ", ";
- }
- if (is_busy)
- {
- line += LLTrans::getString("AvatarBusy");
- line += ", ";
- }
- if (is_muted)
- {
- line += LLTrans::getString("AvatarMuted");
- line += ", ";
- }
- if (is_appearance)
- {
- line += LLTrans::getString("AvatarEditingAppearance");
- line += ", ";
- }
- if (is_cloud)
- {
- line += LLTrans::getString("LoadingData");
- line += ", ";
- }
- // trim last ", "
- line.resize( line.length() - 2 );
- addNameTagLine(line, name_tag_color, LLFontGL::NORMAL,
- LLFontGL::getFontSansSerifSmall());
- }
-
- if (sRenderGroupTitles
- && title && title->getString() && title->getString()[0] != '\0')
- {
- std::string title_str = title->getString();
- LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR);
- addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL,
- LLFontGL::getFontSansSerifSmall());
- }
-
- static LLUICachedControl<bool> show_display_names("NameTagShowDisplayNames");
- static LLUICachedControl<bool> show_usernames("NameTagShowUsernames");
-
- if (LLAvatarNameCache::useDisplayNames())
- {
- LLAvatarName av_name;
- if (!LLAvatarNameCache::get(getID(), &av_name))
- {
- // ...call this function back when the name arrives
- // and force a rebuild
- LLAvatarNameCache::get(getID(),
- boost::bind(&LLVOAvatar::clearNameTag, this));
- }
-
- // Might be blank if name not available yet, that's OK
- if (show_display_names)
- {
- addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL,
- LLFontGL::getFontSansSerif());
- }
- // Suppress SLID display if display name matches exactly (ugh)
- if (show_usernames && !av_name.mIsDisplayNameDefault)
- {
- // *HACK: Desaturate the color
- LLColor4 username_color = name_tag_color * 0.83f;
- addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL,
- LLFontGL::getFontSansSerifSmall());
- }
- }
- else
- {
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- std::string full_name =
- LLCacheName::buildFullName( firstname->getString(), lastname->getString() );
- addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font);
- }
-
- mNameAway = is_away;
- mNameBusy = is_busy;
- mNameMute = is_muted;
- mNameAppearance = is_appearance;
- mNameFriend = is_friend;
- mNameCloud = is_cloud;
- mTitle = title ? title->getString() : "";
- LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR);
- new_name = TRUE;
- }
-
- if (mVisibleChat)
- {
- mNameText->setFont(LLFontGL::getFontSansSerif());
- mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT);
- mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f);
-
- char line[MAX_STRING]; /* Flawfinder: ignore */
- line[0] = '\0';
- std::deque<LLChat>::iterator chat_iter = mChats.begin();
- mNameText->clearString();
-
- LLColor4 new_chat = LLUIColorTable::instance().getColor( isSelf() ? "UserChatColor" : "AgentChatColor" );
- LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f);
- LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f);
- if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES)
- {
- ++chat_iter;
- }
-
- for(; chat_iter != mChats.end(); ++chat_iter)
- {
- F32 chat_fade_amt = llclamp((F32)((LLFrameTimer::getElapsedSeconds() - chat_iter->mTime) / CHAT_FADE_TIME), 0.f, 4.f);
- LLFontGL::StyleFlags style;
- switch(chat_iter->mChatType)
- {
- case CHAT_TYPE_WHISPER:
- style = LLFontGL::ITALIC;
- break;
- case CHAT_TYPE_SHOUT:
- style = LLFontGL::BOLD;
- break;
- default:
- style = LLFontGL::NORMAL;
- break;
- }
- if (chat_fade_amt < 1.f)
- {
- F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f);
- mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style);
- }
- else if (chat_fade_amt < 2.f)
- {
- F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f);
- mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style);
- }
- else if (chat_fade_amt < 3.f)
- {
- // *NOTE: only remove lines down to minimum number
- mNameText->addLine(chat_iter->mText, old_chat, style);
- }
- }
- mNameText->setVisibleOffScreen(TRUE);
-
- if (mTyping)
- {
- S32 dot_count = (llfloor(mTypingTimer.getElapsedTimeF32() * 3.f) + 2) % 3 + 1;
- switch(dot_count)
- {
- case 1:
- mNameText->addLine(".", new_chat);
- break;
- case 2:
- mNameText->addLine("..", new_chat);
- break;
- case 3:
- mNameText->addLine("...", new_chat);
- break;
- }
-
- }
- }
- else
- {
- // ...not using chat bubbles, just names
- mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER);
- mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
- mNameText->setVisibleOffScreen(FALSE);
- }
-}
-
-void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font)
-{
- llassert(mNameText);
- if (mVisibleChat)
- {
- mNameText->addLabel(line);
- }
- else
- {
- mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font);
- }
- mNameString += line;
- mNameString += '\n';
-}
-
-void LLVOAvatar::clearNameTag()
-{
- mNameString.clear();
- if (mNameText)
- {
- mNameText->setLabel("");
- mNameText->setString( "" );
- }
-}
-
-//static
-void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id)
-{
- LLViewerObject* obj = gObjectList.findObject(agent_id);
- if (!obj) return;
-
- LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj);
- if (!avatar) return;
-
- avatar->clearNameTag();
-}
-
-//static
-void LLVOAvatar::invalidateNameTags()
-{
- std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
- for ( ; it != LLCharacter::sInstances.end(); ++it)
- {
- LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it);
- if (!avatar) continue;
- if (avatar->isDead()) continue;
-
- avatar->clearNameTag();
-
- }
-}
-
-// Compute name tag position during idle update
-LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
-{
- LLQuaternion root_rot = mRoot.getWorldRotation();
- LLVector3 pixel_right_vec;
- LLVector3 pixel_up_vec;
- LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec);
- LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin();
- camera_to_av.normalize();
- LLVector3 local_camera_at = camera_to_av * ~root_rot;
- LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis();
- local_camera_up.normalize();
- local_camera_up = local_camera_up * ~root_rot;
-
- local_camera_up.scaleVec(mBodySize * 0.5f);
- local_camera_at.scaleVec(mBodySize * 0.5f);
-
- LLVector3 name_position = mRoot.getWorldPosition();
- name_position[VZ] -= mPelvisToFoot;
- name_position[VZ] += (mBodySize[VZ]* 0.55f);
- name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av));
- name_position += pixel_up_vec * 15.f;
-
- return name_position;
-}
-
-void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha)
-{
- llassert(mNameText);
-
- if (new_name
- || alpha != mNameAlpha)
- {
- mNameText->setAlpha(alpha);
- mNameAlpha = alpha;
- }
-}
-
-LLColor4 LLVOAvatar::getNameTagColor(bool is_friend)
-{
- static LLUICachedControl<bool> show_friends("NameTagShowFriends");
- const char* color_name;
- if (show_friends && is_friend)
- {
- color_name = "NameTagFriend";
- }
- else if (LLAvatarNameCache::useDisplayNames())
- {
- // ...color based on whether username "matches" a computed display
- // name
- LLAvatarName av_name;
- if (LLAvatarNameCache::get(getID(), &av_name)
- && av_name.mIsDisplayNameDefault)
- {
- color_name = "NameTagMatch";
- }
- else
- {
- color_name = "NameTagMismatch";
- }
- }
- else
- {
- // ...not using display names
- color_name = "NameTagLegacy";
- }
- return LLUIColorTable::getInstance()->getColor( color_name );
-}
-
-void LLVOAvatar::idleUpdateBelowWater()
-{
- F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]);
-
- F32 water_height;
- water_height = getRegion()->getWaterHeight();
-
- mBelowWater = avatar_height < water_height;
-}
-
-void LLVOAvatar::slamPosition()
-{
- gAgent.setPositionAgent(getPositionAgent());
- mRoot.setWorldPosition(getPositionAgent()); // teleport
- setChanged(TRANSLATED);
- if (mDrawable.notNull())
- {
- gPipeline.updateMoveNormalAsync(mDrawable);
- }
- mRoot.updateWorldMatrixChildren();
-}
-
-//------------------------------------------------------------------------
-// updateCharacter()
-// called on both your avatar and other avatars
-//------------------------------------------------------------------------
-BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- // clear debug text
- mDebugText.clear();
- if (LLVOAvatar::sShowAnimationDebug)
- {
- for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
- iter != mMotionController.getActiveMotions().end(); ++iter)
- {
- LLMotion* motionp = *iter;
- if (motionp->getMinPixelArea() < getPixelArea())
- {
- std::string output;
- if (motionp->getName().empty())
- {
- output = llformat("%s - %d",
- gAgent.isGodlikeWithoutAdminMenuFakery() ?
- motionp->getID().asString().c_str() :
- LLUUID::null.asString().c_str(),
- (U32)motionp->getPriority());
- }
- else
- {
- output = llformat("%s - %d",
- motionp->getName().c_str(),
- (U32)motionp->getPriority());
- }
- addDebugText(output);
- }
- }
- }
-
- if (gNoRender)
- {
- // Hack if we're running drones...
- if (isSelf())
- {
- gAgent.setPositionAgent(getPositionAgent());
- }
- return FALSE;
- }
-
-
- LLVector3d root_pos_global;
-
- if (!mIsBuilt)
- {
- return FALSE;
- }
-
- BOOL visible = isVisible();
-
- // For fading out the names above heads, only let the timer
- // run if we're visible.
- if (mDrawable.notNull() && !visible)
- {
- mTimeVisible.reset();
- }
-
-
- //--------------------------------------------------------------------
- // the rest should only be done occasionally for far away avatars
- //--------------------------------------------------------------------
-
- if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
- {
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- LLVector4a size;
- size.setSub(ext[1],ext[0]);
- F32 mag = size.getLength3().getF32()*0.5f;
-
- F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
- if (LLMuteList::getInstance()->isMuted(getID()))
- { // muted avatars update at 16 hz
- mUpdatePeriod = 16;
- }
- else if (mVisibilityRank <= LLVOAvatar::sMaxVisible ||
- mDrawable->mDistanceWRTCamera < 1.f + mag)
- { //first 25% of max visible avatars are not impostored
- //also, don't impostor avatars whose bounding box may be penetrating the
- //impostor camera near clip plane
- mUpdatePeriod = 1;
- }
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4)
- { //background avatars are REALLY slow updating impostors
- mUpdatePeriod = 16;
- }
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3)
- { //back 25% of max visible avatars are slow updating impostors
- mUpdatePeriod = 8;
- }
- else if (mImpostorPixelArea <= impostor_area)
- { // stuff in between gets an update period based on pixel area
- mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8);
- }
- else
- {
- //nearby avatars, update the impostors more frequently.
- mUpdatePeriod = 4;
- }
-
- visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
- }
-
- // don't early out for your own avatar, as we rely on your animations playing reliably
- // for example, the "turn around" animation when entering customize avatar needs to trigger
- // even when your avatar is offscreen
- if (!visible && !isSelf())
- {
- updateMotions(LLCharacter::HIDDEN_UPDATE);
- return FALSE;
- }
-
- // change animation time quanta based on avatar render load
- if (!isSelf() && !mIsDummy)
- {
- F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);
- F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);
- F32 time_step = time_quantum * pixel_area_scale;
- if (time_step != 0.f)
- {
- // disable walk motion servo controller as it doesn't work with motion timesteps
- stopMotion(ANIM_AGENT_WALK_ADJUST);
- removeAnimationData("Walk Speed");
- }
- mMotionController.setTimeStep(time_step);
-// llinfos << "Setting timestep to " << time_quantum * pixel_area_scale << llendl;
- }
-
- if (getParent() && !mIsSitting)
- {
- sitOnObject((LLViewerObject*)getParent());
- }
- else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
- {
- getOffObject();
- }
-
- //--------------------------------------------------------------------
- // create local variables in world coords for region position values
- //--------------------------------------------------------------------
- F32 speed;
- LLVector3 normal;
-
- LLVector3 xyVel = getVelocity();
- xyVel.mV[VZ] = 0.0f;
- speed = xyVel.length();
-
- BOOL throttle = TRUE;
-
- if (!(mIsSitting && getParent()))
- {
- //--------------------------------------------------------------------
- // get timing info
- // handle initial condition case
- //--------------------------------------------------------------------
- F32 animation_time = mAnimTimer.getElapsedTimeF32();
- if (mTimeLast == 0.0f)
- {
- mTimeLast = animation_time;
- throttle = FALSE;
-
- // put the pelvis at slaved position/mRotation
- mRoot.setWorldPosition( getPositionAgent() ); // first frame
- mRoot.setWorldRotation( getRotation() );
- }
-
- //--------------------------------------------------------------------
- // dont' let dT get larger than 1/5th of a second
- //--------------------------------------------------------------------
- F32 deltaTime = animation_time - mTimeLast;
-
- deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX );
- mTimeLast = animation_time;
-
- mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f);
-
- //--------------------------------------------------------------------
- // compute the position of the avatar's root
- //--------------------------------------------------------------------
- LLVector3d root_pos;
- LLVector3d ground_under_pelvis;
-
- if (isSelf())
- {
- gAgent.setPositionAgent(getRenderPosition());
- }
-
- root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());
-
- resolveHeightGlobal(root_pos, ground_under_pelvis, normal);
- F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);
- BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||
- foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE);
-
- if (in_air && !mInAir)
- {
- mTimeInAir.reset();
- }
- mInAir = in_air;
-
- // correct for the fact that the pelvis is not necessarily the center
- // of the agent's physical representation
- root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot;
-
- LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
-
- if (newPosition != mRoot.getXform()->getWorldPosition())
- {
- mRoot.touch();
- mRoot.setWorldPosition( newPosition ); // regular update
- }
-
-
- //--------------------------------------------------------------------
- // Propagate viewer object rotation to root of avatar
- //--------------------------------------------------------------------
- if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
- {
- LLQuaternion iQ;
- LLVector3 upDir( 0.0f, 0.0f, 1.0f );
-
- // Compute a forward direction vector derived from the primitive rotation
- // and the velocity vector. When walking or jumping, don't let body deviate
- // more than 90 from the view, if necessary, flip the velocity vector.
-
- LLVector3 primDir;
- if (isSelf())
- {
- primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector());
- primDir.normalize();
- }
- else
- {
- primDir = getRotation().getMatrix3().getFwdRow();
- }
- LLVector3 velDir = getVelocity();
- velDir.normalize();
- if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())
- {
- F32 vpD = velDir * primDir;
- if (vpD < -0.5f)
- {
- velDir *= -1.0f;
- }
- }
- LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f));
- if (isSelf() && gAgentCamera.cameraMouselook())
- {
- // make sure fwdDir stays in same general direction as primdir
- if (gAgent.getFlying())
- {
- fwdDir = LLViewerCamera::getInstance()->getAtAxis();
- }
- else
- {
- LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
- LLVector3 up_vector = gAgent.getReferenceUpVector();
- at_axis -= up_vector * (at_axis * up_vector);
- at_axis.normalize();
-
- F32 dot = fwdDir * at_axis;
- if (dot < 0.f)
- {
- fwdDir -= 2.f * at_axis * dot;
- fwdDir.normalize();
- }
- }
-
- }
-
- LLQuaternion root_rotation = mRoot.getWorldMatrix().quaternion();
- F32 root_roll, root_pitch, root_yaw;
- root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
-
- // When moving very slow, the pelvis is allowed to deviate from the
- // forward direction to allow it to hold it's position while the torso
- // and head turn. Once in motion, it must conform however.
- BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
-
- LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV );
- F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, PELVIS_ROT_THRESHOLD_SLOW, PELVIS_ROT_THRESHOLD_FAST);
-
- if (self_in_mouselook)
- {
- pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR;
- }
- pelvis_rot_threshold *= DEG_TO_RAD;
-
- F32 angle = angle_between( pelvisDir, fwdDir );
-
- // The avatar's root is allowed to have a yaw that deviates widely
- // from the forward direction, but if roll or pitch are off even
- // a little bit we need to correct the rotation.
- if(root_roll < 1.f * DEG_TO_RAD
- && root_pitch < 5.f * DEG_TO_RAD)
- {
- // smaller correction vector means pelvis follows prim direction more closely
- if (!mTurning && angle > pelvis_rot_threshold*0.75f)
- {
- mTurning = TRUE;
- }
-
- // use tighter threshold when turning
- if (mTurning)
- {
- pelvis_rot_threshold *= 0.4f;
- }
-
- // am I done turning?
- if (angle < pelvis_rot_threshold)
- {
- mTurning = FALSE;
- }
-
- LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f);
- fwdDir += correction_vector;
- }
- else
- {
- mTurning = FALSE;
- }
-
- // Now compute the full world space rotation for the whole body (wQv)
- LLVector3 leftDir = upDir % fwdDir;
- leftDir.normalize();
- fwdDir = leftDir % upDir;
- LLQuaternion wQv( fwdDir, leftDir, upDir );
-
- if (isSelf() && mTurning)
- {
- if ((fwdDir % pelvisDir) * upDir > 0.f)
- {
- gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT);
- }
- else
- {
- gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT);
- }
- }
-
- // Set the root rotation, but do so incrementally so that it
- // lags in time by some fixed amount.
- //F32 u = LLCriticalDamp::getInterpolant(PELVIS_LAG);
- F32 pelvis_lag_time = 0.f;
- if (self_in_mouselook)
- {
- pelvis_lag_time = PELVIS_LAG_MOUSELOOK;
- }
- else if (mInAir)
- {
- pelvis_lag_time = PELVIS_LAG_FLYING;
- // increase pelvis lag time when moving slowly
- pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f);
- }
- else
- {
- pelvis_lag_time = PELVIS_LAG_WALKING;
- }
-
- F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);
-
- mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) );
-
- }
- }
- else if (mDrawable.notNull())
- {
- mRoot.setPosition(mDrawable->getPosition());
- mRoot.setRotation(mDrawable->getRotation());
- }
-
- //-------------------------------------------------------------------------
- // Update character motions
- //-------------------------------------------------------------------------
- // store data relevant to motions
- mSpeed = speed;
-
- // update animations
- if (mSpecialRenderMode == 1) // Animation Preview
- updateMotions(LLCharacter::FORCE_UPDATE);
- else
- updateMotions(LLCharacter::NORMAL_UPDATE);
-
- // update head position
- updateHeadOffset();
-
- //-------------------------------------------------------------------------
- // Find the ground under each foot, these are used for a variety
- // of things that follow
- //-------------------------------------------------------------------------
- LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
-
- LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
- LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
- resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
- resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
-
- F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
- F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
-
- if (!mIsSitting)
- {
- //-------------------------------------------------------------------------
- // Figure out which foot is on ground
- //-------------------------------------------------------------------------
- if (!mInAir)
- {
- if ((leftElev < 0.0f) || (rightElev < 0.0f))
- {
- ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- ankle_right_pos_agent = mFootRightp->getWorldPosition();
- leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
- rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
- }
- }
- }
-
- //-------------------------------------------------------------------------
- // Generate footstep sounds when feet hit the ground
- //-------------------------------------------------------------------------
- const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
- const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
-
- if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
- {
- BOOL playSound = FALSE;
- LLVector3 foot_pos_agent;
-
- BOOL onGroundLeft = (leftElev <= 0.05f);
- BOOL onGroundRight = (rightElev <= 0.05f);
-
- // did left foot hit the ground?
- if ( onGroundLeft && !mWasOnGroundLeft )
- {
- foot_pos_agent = ankle_left_pos_agent;
- playSound = TRUE;
- }
-
- // did right foot hit the ground?
- if ( onGroundRight && !mWasOnGroundRight )
- {
- foot_pos_agent = ankle_right_pos_agent;
- playSound = TRUE;
- }
-
- mWasOnGroundLeft = onGroundLeft;
- mWasOnGroundRight = onGroundRight;
-
- if ( playSound )
- {
-// F32 gain = clamp_rescale( mSpeedAccum,
-// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED,
-// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN );
-
- const F32 STEP_VOLUME = 0.1f;
- const LLUUID& step_sound_id = getStepSound();
-
- LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
-
- if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
- && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
- {
- gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
- }
- }
- }
-
- mRoot.updateWorldMatrixChildren();
-
- if (!mDebugText.size() && mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
- else if (mDebugText.size())
- {
- setDebugText(mDebugText);
- }
-
- //mesh vertices need to be reskinned
- mNeedsSkin = TRUE;
-
- return TRUE;
-}
-//-----------------------------------------------------------------------------
-// updateHeadOffset()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateHeadOffset()
-{
- // since we only care about Z, just grab one of the eyes
- LLVector3 midEyePt = mEyeLeftp->getWorldPosition();
- midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot.getWorldPosition();
- midEyePt.mV[VZ] = llmax(-mPelvisToFoot + LLViewerCamera::getInstance()->getNear(), midEyePt.mV[VZ]);
-
- if (mDrawable.notNull())
- {
- midEyePt = midEyePt * ~mDrawable->getWorldRotation();
- }
- if (mIsSitting)
- {
- mHeadOffset = midEyePt;
- }
- else
- {
- F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped));
- mHeadOffset = lerp(midEyePt, mHeadOffset, u);
- }
-}
-//------------------------------------------------------------------------
-// setPelvisOffset
-//------------------------------------------------------------------------
-void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, F32 pelvisFixup )
-{
- mHasPelvisOffset = hasOffset;
- if ( mHasPelvisOffset )
- {
- //Store off last pelvis to foot value
- mLastPelvisToFoot = mPelvisToFoot;
- mPelvisOffset = offsetAmount;
- mLastPelvisFixup = mPelvisFixup;
- mPelvisFixup = pelvisFixup;
- }
-}
-//------------------------------------------------------------------------
-// postPelvisSetRecalc
-//------------------------------------------------------------------------
-void LLVOAvatar::postPelvisSetRecalc( void )
-{
- computeBodySize();
- mRoot.touch();
- mRoot.updateWorldMatrixChildren();
- dirtyMesh();
- updateHeadOffset();
-}
-//------------------------------------------------------------------------
-// pelisPoke
-//------------------------------------------------------------------------
-void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
-{
- mHasPelvisOffset = true;
- mLastPelvisFixup = mPelvisFixup;
- mPelvisFixup = pelvisFixupAmount;
-}
-//------------------------------------------------------------------------
-// updateVisibility()
-//------------------------------------------------------------------------
-void LLVOAvatar::updateVisibility()
-{
- BOOL visible = FALSE;
-
- if (mIsDummy)
- {
- visible = TRUE;
- }
- else if (mDrawable.isNull())
- {
- visible = FALSE;
- }
- else
- {
- if (!mDrawable->getSpatialGroup() || mDrawable->getSpatialGroup()->isVisible())
- {
- visible = TRUE;
- }
- else
- {
- visible = FALSE;
- }
-
- if(isSelf())
- {
- if (!gAgentWearables.areWearablesLoaded())
- {
- visible = FALSE;
- }
- }
- else if( !mFirstAppearanceMessageReceived )
- {
- visible = FALSE;
- }
-
- if (sDebugInvisible)
- {
- LLNameValue* firstname = getNVPair("FirstName");
- if (firstname)
- {
- llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl;
- }
- else
- {
- llinfos << "Avatar " << this << " updating visiblity" << llendl;
- }
-
- if (visible)
- {
- llinfos << "Visible" << llendl;
- }
- else
- {
- llinfos << "Not visible" << llendl;
- }
-
- /*if (avatar_in_frustum)
- {
- llinfos << "Avatar in frustum" << llendl;
- }
- else
- {
- llinfos << "Avatar not in frustum" << llendl;
- }*/
-
- /*if (LLViewerCamera::getInstance()->sphereInFrustum(sel_pos_agent, 2.0f))
- {
- llinfos << "Sel pos visible" << llendl;
- }
- if (LLViewerCamera::getInstance()->sphereInFrustum(wrist_right_pos_agent, 0.2f))
- {
- llinfos << "Wrist pos visible" << llendl;
- }
- if (LLViewerCamera::getInstance()->sphereInFrustum(getPositionAgent(), getMaxScale()*2.f))
- {
- llinfos << "Agent visible" << llendl;
- }*/
- llinfos << "PA: " << getPositionAgent() << llendl;
- /*llinfos << "SPA: " << sel_pos_agent << llendl;
- llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
-
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- if (LLViewerObject *attached_object = (*attachment_iter))
- {
- if(attached_object->mDrawable->isVisible())
- {
- llinfos << attachment->getName() << " visible" << llendl;
- }
- else
- {
- llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl;
- }
- }
- }
- }
- }
- }
-
- if (!visible && mVisible)
- {
- mMeshInvisibleTime.reset();
- }
-
- if (visible)
- {
- if (!mMeshValid)
- {
- restoreMeshData();
- }
- }
- else
- {
- if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)
- {
- releaseMeshData();
- }
- // this breaks off-screen chat bubbles
- //if (mNameText)
- //{
- // mNameText->markDead();
- // mNameText = NULL;
- // sNumVisibleChatBubbles--;
- //}
- }
-
- mVisible = visible;
-}
-
-// private
-bool LLVOAvatar::shouldAlphaMask()
-{
- const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked
- && !LLDrawPoolAvatar::sSkipTransparent;
-
- return should_alpha_mask;
-
-}
-
-U32 LLVOAvatar::renderSkinnedAttachments()
-{
- /*U32 num_indices = 0;
-
- const U32 data_mask = LLVertexBuffer::MAP_VERTEX |
- LLVertexBuffer::MAP_NORMAL |
- LLVertexBuffer::MAP_TEXCOORD0 |
- LLVertexBuffer::MAP_COLOR |
- LLVertexBuffer::MAP_WEIGHT4;
-
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isHUDAttachment())
- {
- const LLDrawable* drawable = attached_object->mDrawable;
- if (drawable)
- {
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- if (face->isState(LLFace::RIGGED))
- {
-
- }
- }
- }
- }
-
- return num_indices;*/
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-// renderSkinned()
-//-----------------------------------------------------------------------------
-U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
-{
- U32 num_indices = 0;
-
- if (!mIsBuilt)
- {
- return num_indices;
- }
-
- LLFace* face = mDrawable->getFace(0);
-
- bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
-
- if (needs_rebuild || mDirtyMesh)
- { //LOD changed or new mesh created, allocate new vertex buffer if needed
- if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4)
- {
- updateMeshData();
- mDirtyMesh = 0;
- mNeedsSkin = TRUE;
- mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
- }
- }
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0)
- {
- if (mNeedsSkin)
- {
- //generate animated mesh
- mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry();
- mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry();
-
- if( isWearingWearableType( LLWearableType::WT_SKIRT ) )
- {
- mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry();
- }
-
- if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
- {
- mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry();
- mMeshLOD[MESH_ID_HEAD]->updateJointGeometry();
- mMeshLOD[MESH_ID_HAIR]->updateJointGeometry();
- }
- mNeedsSkin = FALSE;
- mLastSkinTime = gFrameTimeSeconds;
-
- LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer();
- if (vb)
- {
- vb->setBuffer(0);
- }
- }
- }
- else
- {
- mNeedsSkin = FALSE;
- }
-
- if (sDebugInvisible)
- {
- LLNameValue* firstname = getNVPair("FirstName");
- if (firstname)
- {
- llinfos << "Avatar " << firstname->getString() << " in render" << llendl;
- }
- else
- {
- llinfos << "Avatar " << this << " in render" << llendl;
- }
- if (!mIsBuilt)
- {
- llinfos << "Not built!" << llendl;
- }
- else if (!gAgent.needsRenderAvatar())
- {
- llinfos << "Doesn't need avatar render!" << llendl;
- }
- else
- {
- llinfos << "Rendering!" << llendl;
- }
- }
-
- if (!mIsBuilt)
- {
- return num_indices;
- }
-
- if (isSelf() && !gAgent.needsRenderAvatar())
- {
- return num_indices;
- }
-
- // render collision normal
- // *NOTE: this is disabled (there is no UI for enabling sShowFootPlane) due
- // to DEV-14477. the code is left here to aid in tracking down the cause
- // of the crash in the future. -brad
- if (sShowFootPlane && mDrawable.notNull())
- {
- LLVector3 slaved_pos = mDrawable->getPositionAgent();
- LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]);
- F32 dist_from_plane = (slaved_pos * foot_plane_normal) - mFootPlane.mV[VW];
- LLVector3 collide_point = slaved_pos;
- collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE);
-
- gGL.begin(LLRender::LINES);
- {
- F32 SQUARE_SIZE = 0.2f;
- gGL.color4f(1.f, 0.f, 0.f, 1.f);
-
- gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
- gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-
- gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
- gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-
- gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
- gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
-
- gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
- gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
-
- gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]);
- gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]);
-
- }
- gGL.end();
- gGL.flush();
- }
- //--------------------------------------------------------------------
- // render all geometry attached to the skeleton
- //--------------------------------------------------------------------
- static LLStat render_stat;
-
- LLViewerJointMesh::sRenderPass = pass;
-
- if (pass == AVATAR_RENDER_PASS_SINGLE)
- {
-
- bool should_alpha_mask = shouldAlphaMask();
- LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
-
- if (should_alpha_mask)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
- }
-
- BOOL first_pass = TRUE;
- if (!LLDrawPoolAvatar::sSkipOpaque)
- {
- if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
- {
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
- {
- num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy);
- first_pass = FALSE;
- }
- }
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
- {
- num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
- first_pass = FALSE;
- }
-
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
- {
- num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
- first_pass = FALSE;
- }
- }
-
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-
- if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender)
- {
- LLGLState blend(GL_BLEND, !mIsDummy);
- LLGLState test(GL_ALPHA_TEST, !mIsDummy);
- num_indices += renderTransparent(first_pass);
- }
- }
-
- LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
-
- //llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl;
-
- //render_stat.addValue(render_timer.getElapsedTimeF32()*1000.f);
-
- return num_indices;
-}
-
-U32 LLVOAvatar::renderTransparent(BOOL first_pass)
-{
- U32 num_indices = 0;
- if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
- num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE);
- first_pass = FALSE;
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- }
-
- if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
- {
- if (LLPipeline::sImpostorRender)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
- }
-
- if (isTextureVisible(TEX_HEAD_BAKED))
- {
- num_indices += mMeshLOD[MESH_ID_EYELASH]->render(mAdjustedPixelArea, first_pass, mIsDummy);
- first_pass = FALSE;
- }
- // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
- // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
- if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy);
- first_pass = FALSE;
- }
- if (LLPipeline::sImpostorRender)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- }
- }
-
- return num_indices;
-}
-
-//-----------------------------------------------------------------------------
-// renderRigid()
-//-----------------------------------------------------------------------------
-U32 LLVOAvatar::renderRigid()
-{
- U32 num_indices = 0;
-
- if (!mIsBuilt)
- {
- return 0;
- }
-
- if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead()))
- {
- return 0;
- }
-
- if (!mIsBuilt)
- {
- return 0;
- }
-
- bool should_alpha_mask = shouldAlphaMask();
- LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
-
- if (should_alpha_mask)
- {
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
- }
-
- if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
- {
- num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
- num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
- }
-
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-
- return num_indices;
-}
-
-U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
-{
- if (!mImpostor.isComplete())
- {
- return 0;
- }
-
- LLVector3 pos(getRenderPosition()+mImpostorOffset);
- LLVector3 at = (pos - LLViewerCamera::getInstance()->getOrigin());
- at.normalize();
- LLVector3 left = LLViewerCamera::getInstance()->getUpAxis() % at;
- LLVector3 up = at%left;
-
- left *= mImpostorDim.mV[0];
- up *= mImpostorDim.mV[1];
-
- LLGLEnable test(GL_ALPHA_TEST);
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
-
- gGL.color4ubv(color.mV);
- gGL.getTexUnit(diffuse_channel)->bind(&mImpostor);
- gGL.begin(LLRender::QUADS);
- gGL.texCoord2f(0,0);
- gGL.vertex3fv((pos+left-up).mV);
- gGL.texCoord2f(1,0);
- gGL.vertex3fv((pos-left-up).mV);
- gGL.texCoord2f(1,1);
- gGL.vertex3fv((pos-left+up).mV);
- gGL.texCoord2f(0,1);
- gGL.vertex3fv((pos+left+up).mV);
- gGL.end();
- gGL.flush();
-
- return 6;
-}
-
-//------------------------------------------------------------------------
-// LLVOAvatar::updateTextures()
-//------------------------------------------------------------------------
-void LLVOAvatar::updateTextures()
-{
- BOOL render_avatar = TRUE;
-
- if (mIsDummy || gNoRender)
- {
- return;
- }
-
- if( isSelf() )
- {
- render_avatar = TRUE;
- }
- else
- {
- if(!isVisible())
- {
- return ;//do not update for invisible avatar.
- }
-
- render_avatar = !mCulled; //visible and not culled.
- }
-
- std::vector<BOOL> layer_baked;
- // GL NOT ACTIVE HERE - *TODO
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex));
- // bind the texture so that they'll be decoded slightly
- // inefficient, we can short-circuit this if we have to
- if (render_avatar && !gGLManager.mIsDisabled)
- {
- if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded)
- {
- gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ));
- }
- }
- }
-
- mMaxPixelArea = 0.f;
- mMinPixelArea = 99999999.f;
- mHasGrey = FALSE; // debug
- for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++)
- {
- LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index);
- U32 num_wearables = gAgentWearables.getWearableCount(wearable_type);
- const LLTextureEntry *te = getTE(texture_index);
- const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT);
- LLViewerFetchedTexture *imagep = NULL;
- for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++)
- {
- imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE);
- if (imagep)
- {
- const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)texture_index);
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- if (texture_dict->mIsLocalTexture)
- {
- addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]);
- }
- }
- }
- if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar)
- {
- const S32 boost_level = getAvatarBakedBoostLevel();
- imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
- // Spam if this is a baked texture, not set to default image, without valid host info
- if (isIndexBakedTexture((ETextureIndex)texture_index)
- && imagep->getID() != IMG_DEFAULT_AVATAR
- && imagep->getID() != IMG_INVISIBLE
- && !imagep->getTargetHost().isOk())
- {
- LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture "
- << imagep->getID() << " for avatar "
- << (isSelf() ? "<myself>" : getID().asString())
- << " on host " << getRegion()->getHost() << llendl;
- }
-
- addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );
- }
- }
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
- {
- setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea)));
- }
-}
-
-
-void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep,
- F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index )
-{
- // No local texture stats for non-self avatars
- return;
-}
-
-const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames.
-const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames
-void LLVOAvatar::checkTextureLoading()
-{
- static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds
-
- BOOL pause = !isVisible() ;
- if(!pause)
- {
- mInvisibleTimer.reset() ;
- }
- if(mLoadedCallbacksPaused == pause)
- {
- return ;
- }
-
- if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty.
- {
- mLoadedCallbacksPaused = pause ;
- return ; //nothing to check.
- }
-
- if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME)
- {
- return ; //have not been invisible for enough time.
- }
-
- for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin();
- iter != mCallbackTextureList.end(); ++iter)
- {
- LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ;
- if(tex)
- {
- if(pause)//pause texture fetching.
- {
- tex->pauseLoadedCallbacks(&mCallbackTextureList) ;
-
- //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames.
- tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL);
- tex->resetMaxVirtualSizeResetCounter() ;
- }
- else//unpause
- {
- static const F32 START_AREA = 100.f ;
-
- tex->unpauseLoadedCallbacks(&mCallbackTextureList) ;
- tex->addTextureStats(START_AREA); //jump start the fetching again
- }
- }
- }
-
- if(!pause)
- {
- updateTextures() ; //refresh texture stats.
- }
- mLoadedCallbacksPaused = pause ;
- return ;
-}
-
-const F32 SELF_ADDITIONAL_PRI = 0.75f ;
-const F32 ADDITIONAL_PRI = 0.5f;
-void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)
-{
- //Note:
- //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames,
- //the texture pipeline will stop fetching this texture.
-
- imagep->resetTextureStats();
- imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures.
- imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
- imagep->resetMaxVirtualSizeResetCounter() ;
-
- mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
- mMinPixelArea = llmin(pixel_area, mMinPixelArea);
- imagep->addTextureStats(pixel_area / texel_area_ratio);
- imagep->setBoostLevel(boost_level);
-
- if(boost_level != LLViewerTexture::BOOST_AVATAR_BAKED_SELF)
- {
- imagep->setAdditionalDecodePriority(ADDITIONAL_PRI) ;
- }
- else
- {
- imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
- }
-}
-
-//virtual
-void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep, const U32 index)
-{
- setTEImage(te, imagep);
-}
-
-//virtual
-LLViewerTexture* LLVOAvatar::getImage(const U8 te, const U32 index) const
-{
- return getTEImage(te);
-}
-//virtual
-const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const
-{
- return getTE(te_num);
-}
-
-//virtual
-void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te)
-{
- setTE(index, te);
-}
-
-//-----------------------------------------------------------------------------
-// resolveHeight()
-//-----------------------------------------------------------------------------
-
-void LLVOAvatar::resolveHeightAgent(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &out_norm)
-{
- LLVector3d in_pos_global, out_pos_global;
-
- in_pos_global = gAgent.getPosGlobalFromAgent(in_pos_agent);
- resolveHeightGlobal(in_pos_global, out_pos_global, out_norm);
- out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global);
-}
-
-
-void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm)
-{
- LLViewerObject *obj;
- LLWorld::getInstance()->resolveStepHeightGlobal(this, start_pt, end_pt, out_pos, out_norm, &obj);
-}
-
-void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm)
-{
- LLVector3d zVec(0.0f, 0.0f, 0.5f);
- LLVector3d p0 = inPos + zVec;
- LLVector3d p1 = inPos - zVec;
- LLViewerObject *obj;
- LLWorld::getInstance()->resolveStepHeightGlobal(this, p0, p1, outPos, outNorm, &obj);
- if (!obj)
- {
- mStepOnLand = TRUE;
- mStepMaterial = 0;
- mStepObjectVelocity.setVec(0.0f, 0.0f, 0.0f);
- }
- else
- {
- mStepOnLand = FALSE;
- mStepMaterial = obj->getMaterial();
-
- // We want the primitive velocity, not our velocity... (which actually subtracts the
- // step object velocity)
- LLVector3 angularVelocity = obj->getAngularVelocity();
- LLVector3 relativePos = gAgent.getPosAgentFromGlobal(outPos) - obj->getPositionAgent();
-
- LLVector3 linearComponent = angularVelocity % relativePos;
-// llinfos << "Linear Component of Rotation Velocity " << linearComponent << llendl;
- mStepObjectVelocity = obj->getVelocity() + linearComponent;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// getStepSound()
-//-----------------------------------------------------------------------------
-const LLUUID& LLVOAvatar::getStepSound() const
-{
- if ( mStepOnLand )
- {
- return sStepSoundOnLand;
- }
-
- return sStepSounds[mStepMaterial];
-}
-
-
-//-----------------------------------------------------------------------------
-// processAnimationStateChanges()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::processAnimationStateChanges()
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- if (gNoRender)
- {
- return;
- }
-
- if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) )
- {
- startMotion(ANIM_AGENT_WALK_ADJUST);
- stopMotion(ANIM_AGENT_FLY_ADJUST);
- }
- else if (mInAir && !mIsSitting)
- {
- stopMotion(ANIM_AGENT_WALK_ADJUST);
- startMotion(ANIM_AGENT_FLY_ADJUST);
- }
- else
- {
- stopMotion(ANIM_AGENT_WALK_ADJUST);
- stopMotion(ANIM_AGENT_FLY_ADJUST);
- }
-
- if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
- {
- startMotion(ANIM_AGENT_TARGET);
- stopMotion(ANIM_AGENT_BODY_NOISE);
- }
- else
- {
- stopMotion(ANIM_AGENT_TARGET);
- startMotion(ANIM_AGENT_BODY_NOISE);
- }
-
- // clear all current animations
- AnimIterator anim_it;
- for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();)
- {
- AnimIterator found_anim = mSignaledAnimations.find(anim_it->first);
-
- // playing, but not signaled, so stop
- if (found_anim == mSignaledAnimations.end())
- {
- processSingleAnimationStateChange(anim_it->first, FALSE);
- mPlayingAnimations.erase(anim_it++);
- continue;
- }
-
- ++anim_it;
- }
-
- // start up all new anims
- for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();)
- {
- AnimIterator found_anim = mPlayingAnimations.find(anim_it->first);
-
- // signaled but not playing, or different sequence id, start motion
- if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second)
- {
- if (processSingleAnimationStateChange(anim_it->first, TRUE))
- {
- mPlayingAnimations[anim_it->first] = anim_it->second;
- ++anim_it;
- continue;
- }
- }
-
- ++anim_it;
- }
-
- // clear source information for animations which have been stopped
- if (isSelf())
- {
- AnimSourceIterator source_it = mAnimationSources.begin();
-
- for (source_it = mAnimationSources.begin(); source_it != mAnimationSources.end();)
- {
- if (mSignaledAnimations.find(source_it->second) == mSignaledAnimations.end())
- {
- mAnimationSources.erase(source_it++);
- }
- else
- {
- ++source_it;
- }
- }
- }
-
- stop_glerror();
-}
-
-
-//-----------------------------------------------------------------------------
-// processSingleAnimationStateChange();
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start )
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- BOOL result = FALSE;
-
- if ( start ) // start animation
- {
- if (anim_id == ANIM_AGENT_TYPE)
- {
- if (gAudiop)
- {
- LLVector3d char_pos_global = gAgent.getPosGlobalFromAgent(getCharacterPosition());
- if (LLViewerParcelMgr::getInstance()->canHearSound(char_pos_global)
- && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
- {
- // RN: uncomment this to play on typing sound at fixed volume once sound engine is fixed
- // to support both spatialized and non-spatialized instances of the same sound
- //if (isSelf())
- //{
- // gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
- //}
- //else
- {
- LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping"));
- gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global);
- }
- }
- }
- }
- else if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED)
- {
- sitDown(TRUE);
- }
-
-
- if (startMotion(anim_id))
- {
- result = TRUE;
- }
- else
- {
- llwarns << "Failed to start motion!" << llendl;
- }
- }
- else //stop animation
- {
- if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED)
- {
- sitDown(FALSE);
- }
- stopMotion(anim_id);
- result = TRUE;
- }
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-// isAnyAnimationSignaled()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const
-{
- for (S32 i = 0; i < num_anims; i++)
- {
- if(mSignaledAnimations.find(anim_array[i]) != mSignaledAnimations.end())
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// resetAnimations()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetAnimations()
-{
- LLKeyframeMotion::flushKeyframeCache();
- flushAllMotions();
-}
-
-// Override selectively based on avatar sex and whether we're using new
-// animations.
-LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
-{
- BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun");
- LLUUID result = id;
-
- // start special case female walk for female avatars
- if (getSex() == SEX_FEMALE)
- {
- if (id == ANIM_AGENT_WALK)
- {
- if (use_new_walk_run)
- result = ANIM_AGENT_FEMALE_WALK_NEW;
- else
- result = ANIM_AGENT_FEMALE_WALK;
- }
- else if (id == ANIM_AGENT_RUN)
- {
- // There is no old female run animation, so only override
- // in one case.
- if (use_new_walk_run)
- result = ANIM_AGENT_FEMALE_RUN_NEW;
- }
- else if (id == ANIM_AGENT_SIT)
- {
- result = ANIM_AGENT_SIT_FEMALE;
- }
- }
- else
- {
- // Male avatar.
- if (id == ANIM_AGENT_WALK)
- {
- if (use_new_walk_run)
- result = ANIM_AGENT_WALK_NEW;
- }
- else if (id == ANIM_AGENT_RUN)
- {
- if (use_new_walk_run)
- result = ANIM_AGENT_RUN_NEW;
- }
-
- }
-
- return result;
-
-}
-
-//-----------------------------------------------------------------------------
-// startMotion()
-// id is the asset if of the animation to start
-// time_offset is the offset into the animation at which to start playing
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
-
- LLUUID remap_id = remapMotionID(id);
-
- if (remap_id != id)
- {
- lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
- }
-
- if (isSelf() && remap_id == ANIM_AGENT_AWAY)
- {
- gAgent.setAFK();
- }
-
- return LLCharacter::startMotion(remap_id, time_offset);
-}
-
-//-----------------------------------------------------------------------------
-// stopMotion()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate)
-{
- lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
-
- LLUUID remap_id = remapMotionID(id);
-
- if (remap_id != id)
- {
- lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
- }
-
- if (isSelf())
- {
- gAgent.onAnimStop(remap_id);
- }
-
- return LLCharacter::stopMotion(remap_id, stop_immediate);
-}
-
-//-----------------------------------------------------------------------------
-// stopMotionFromSource()
-//-----------------------------------------------------------------------------
-// virtual
-void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id)
-{
-}
-
-//-----------------------------------------------------------------------------
-// getVolumePos()
-//-----------------------------------------------------------------------------
-LLVector3 LLVOAvatar::getVolumePos(S32 joint_index, LLVector3& volume_offset)
-{
- if (joint_index > mNumCollisionVolumes)
- {
- return LLVector3::zero;
- }
-
- return mCollisionVolumes[joint_index].getVolumePos(volume_offset);
-}
-
-//-----------------------------------------------------------------------------
-// findCollisionVolume()
-//-----------------------------------------------------------------------------
-LLJoint* LLVOAvatar::findCollisionVolume(U32 volume_id)
-{
- if ((S32)volume_id > mNumCollisionVolumes)
- {
- return NULL;
- }
-
- return &mCollisionVolumes[volume_id];
-}
-
-//-----------------------------------------------------------------------------
-// findCollisionVolume()
-//-----------------------------------------------------------------------------
-S32 LLVOAvatar::getCollisionVolumeID(std::string &name)
-{
- for (S32 i = 0; i < mNumCollisionVolumes; i++)
- {
- if (mCollisionVolumes[i].getName() == name)
- {
- return i;
- }
- }
-
- return -1;
-}
-
-//-----------------------------------------------------------------------------
-// addDebugText()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::addDebugText(const std::string& text)
-{
- mDebugText.append(1, '\n');
- mDebugText.append(text);
-}
-
-//-----------------------------------------------------------------------------
-// getID()
-//-----------------------------------------------------------------------------
-const LLUUID& LLVOAvatar::getID()
-{
- return mID;
-}
-
-//-----------------------------------------------------------------------------
-// getJoint()
-//-----------------------------------------------------------------------------
-// RN: avatar joints are multi-rooted to include screen-based attachments
-LLJoint *LLVOAvatar::getJoint( const std::string &name )
-{
- LLJoint* jointp = mRoot.findJoint(name);
- return jointp;
-}
-
-//-----------------------------------------------------------------------------
-// resetJointPositions
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointPositions( void )
-{
- for(S32 i = 0; i < (S32)mNumJoints; ++i)
- {
- mSkeleton[i].restoreOldXform();
- mSkeleton[i].setId( LLUUID::null );
- }
- mHasPelvisOffset = false;
- mPelvisFixup = mLastPelvisFixup;
-}
-//-----------------------------------------------------------------------------
-// resetSpecificJointPosition
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetSpecificJointPosition( const std::string& name )
-{
- LLJoint* pJoint = mRoot.findJoint( name );
-
- if ( pJoint && pJoint->doesJointNeedToBeReset() )
- {
- pJoint->restoreOldXform();
- pJoint->setId( LLUUID::null );
- //If we're reseting the pelvis position make sure not to apply offset
- if ( name == "mPelvis" )
- {
- mHasPelvisOffset = false;
- }
- }
- else
- {
- llinfos<<"Did not find "<< name.c_str()<<llendl;
- }
-}
-//-----------------------------------------------------------------------------
-// resetJointPositionsToDefault
-//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointPositionsToDefault( void )
-{
- const LLVector3& avPos = getCharacterPosition();
-
- //Reposition the pelvis
- LLJoint* pPelvis = mRoot.findJoint("mPelvis");
- if ( pPelvis )
- {
- pPelvis->setPosition( avPos + pPelvis->getPosition() );
- }
- else
- {
- llwarns<<"Can't get pelvis joint."<<llendl;
- return;
- }
-
- //Subsequent joints are relative to pelvis
- for( S32 i = 0; i < (S32)mNumJoints; ++i )
- {
- LLJoint* pJoint = (LLJoint*)&mSkeleton[i];
- if ( pJoint->doesJointNeedToBeReset() )
- {
-
- pJoint->setId( LLUUID::null );
- //restore joints to default positions, however skip over the pelvis
- if ( pJoint && pPelvis != pJoint )
- {
- pJoint->restoreOldXform();
- }
- }
- }
- //make sure we don't apply the joint offset
- mHasPelvisOffset = false;
- mPelvisFixup = mLastPelvisFixup;
- postPelvisSetRecalc();
-}
-//-----------------------------------------------------------------------------
-// getCharacterPosition()
-//-----------------------------------------------------------------------------
-LLVector3 LLVOAvatar::getCharacterPosition()
-{
- if (mDrawable.notNull())
- {
- return mDrawable->getPositionAgent();
- }
- else
- {
- return getPositionAgent();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getCharacterRotation()
-//-----------------------------------------------------------------------------
-LLQuaternion LLVOAvatar::getCharacterRotation()
-{
- return getRotation();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getCharacterVelocity()
-//-----------------------------------------------------------------------------
-LLVector3 LLVOAvatar::getCharacterVelocity()
-{
- return getVelocity() - mStepObjectVelocity;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getCharacterAngularVelocity()
-//-----------------------------------------------------------------------------
-LLVector3 LLVOAvatar::getCharacterAngularVelocity()
-{
- return getAngularVelocity();
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getGround()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &outNorm)
-{
- LLVector3d z_vec(0.0f, 0.0f, 1.0f);
- LLVector3d p0_global, p1_global;
-
- if (gNoRender || mIsDummy)
- {
- outNorm.setVec(z_vec);
- out_pos_agent = in_pos_agent;
- return;
- }
-
- p0_global = gAgent.getPosGlobalFromAgent(in_pos_agent) + z_vec;
- p1_global = gAgent.getPosGlobalFromAgent(in_pos_agent) - z_vec;
- LLViewerObject *obj;
- LLVector3d out_pos_global;
- LLWorld::getInstance()->resolveStepHeightGlobal(this, p0_global, p1_global, out_pos_global, outNorm, &obj);
- out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global);
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getTimeDilation()
-//-----------------------------------------------------------------------------
-F32 LLVOAvatar::getTimeDilation()
-{
- return mTimeDilation;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getPixelArea()
-//-----------------------------------------------------------------------------
-F32 LLVOAvatar::getPixelArea() const
-{
- if (mIsDummy)
- {
- return 100000.f;
- }
- return mPixelArea;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getHeadMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh* LLVOAvatar::getHeadMesh()
-{
- return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getUpperBodyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh* LLVOAvatar::getUpperBodyMesh()
-{
- return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLVOAvatar::getPosGlobalFromAgent()
-//-----------------------------------------------------------------------------
-LLVector3d LLVOAvatar::getPosGlobalFromAgent(const LLVector3 &position)
-{
- return gAgent.getPosGlobalFromAgent(position);
-}
-
-//-----------------------------------------------------------------------------
-// getPosAgentFromGlobal()
-//-----------------------------------------------------------------------------
-LLVector3 LLVOAvatar::getPosAgentFromGlobal(const LLVector3d &position)
-{
- return gAgent.getPosAgentFromGlobal(position);
-}
-
-//-----------------------------------------------------------------------------
-// allocateCharacterJoints()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::allocateCharacterJoints( U32 num )
-{
- deleteAndClearArray(mSkeleton);
- mNumJoints = 0;
-
- mSkeleton = new LLViewerJoint[num];
-
- for(S32 joint_num = 0; joint_num < (S32)num; joint_num++)
- {
- mSkeleton[joint_num].setJointNum(joint_num);
- }
-
- if (!mSkeleton)
- {
- return FALSE;
- }
-
- mNumJoints = num;
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// allocateCollisionVolumes()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::allocateCollisionVolumes( U32 num )
-{
- deleteAndClearArray(mCollisionVolumes);
- mNumCollisionVolumes = 0;
-
- mCollisionVolumes = new LLViewerJointCollisionVolume[num];
- if (!mCollisionVolumes)
- {
- return FALSE;
- }
-
- mNumCollisionVolumes = num;
- return TRUE;
-}
-
-
-//-----------------------------------------------------------------------------
-// getCharacterJoint()
-//-----------------------------------------------------------------------------
-LLJoint *LLVOAvatar::getCharacterJoint( U32 num )
-{
- if ((S32)num >= mNumJoints
- || (S32)num < 0)
- {
- return NULL;
- }
- return (LLJoint*)&mSkeleton[num];
-}
-
-//-----------------------------------------------------------------------------
-// requestStopMotion()
-//-----------------------------------------------------------------------------
-// virtual
-void LLVOAvatar::requestStopMotion( LLMotion* motion )
-{
- // Only agent avatars should handle the stop motion notifications.
-}
-
-//-----------------------------------------------------------------------------
-// loadAvatar()
-//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar");
-
-BOOL LLVOAvatar::loadAvatar()
-{
-// LLFastTimer t(FTM_LOAD_AVATAR);
-
- // avatar_skeleton.xml
- if( !buildSkeleton(sAvatarSkeletonInfo) )
- {
- llwarns << "avatar file: buildSkeleton() failed" << llendl;
- return FALSE;
- }
-
- // avatar_lad.xml : <skeleton>
- if( !loadSkeletonNode() )
- {
- llwarns << "avatar file: loadNodeSkeleton() failed" << llendl;
- return FALSE;
- }
-
- // avatar_lad.xml : <mesh>
- if( !loadMeshNodes() )
- {
- llwarns << "avatar file: loadNodeMesh() failed" << llendl;
- return FALSE;
- }
-
- // avatar_lad.xml : <global_color>
- if( sAvatarXmlInfo->mTexSkinColorInfo )
- {
- mTexSkinColor = new LLTexGlobalColor( this );
- if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
- {
- llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl;
- return FALSE;
- }
- }
- else
- {
- llwarns << "<global_color> name=\"skin_color\" not found" << llendl;
- return FALSE;
- }
- if( sAvatarXmlInfo->mTexHairColorInfo )
- {
- mTexHairColor = new LLTexGlobalColor( this );
- if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
- {
- llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl;
- return FALSE;
- }
- }
- else
- {
- llwarns << "<global_color> name=\"hair_color\" not found" << llendl;
- return FALSE;
- }
- if( sAvatarXmlInfo->mTexEyeColorInfo )
- {
- mTexEyeColor = new LLTexGlobalColor( this );
- if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
- {
- llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl;
- return FALSE;
- }
- }
- else
- {
- llwarns << "<global_color> name=\"eye_color\" not found" << llendl;
- return FALSE;
- }
-
- // avatar_lad.xml : <layer_set>
- if (sAvatarXmlInfo->mLayerInfoList.empty())
- {
- llwarns << "avatar file: missing <layer_set> node" << llendl;
- return FALSE;
- }
-
- if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
- {
- llwarns << "avatar file: missing <morph_masks> node" << llendl;
- return FALSE;
- }
-
- // avatar_lad.xml : <morph_masks>
- for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin();
- iter != sAvatarXmlInfo->mMorphMaskInfoList.end();
- ++iter)
- {
- LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter;
-
- EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion);
- if (baked != BAKED_NUM_INDICES)
- {
- LLPolyMorphTarget *morph_param;
- const std::string *name = &info->mName;
- morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str()));
- if (morph_param)
- {
- BOOL invert = info->mInvert;
- addMaskedMorph(baked, morph_param, invert, info->mLayer);
- }
- }
-
- }
-
- loadLayersets();
-
- // avatar_lad.xml : <driver_parameters>
- for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin();
- iter != sAvatarXmlInfo->mDriverInfoList.end();
- ++iter)
- {
- LLDriverParamInfo *info = *iter;
- LLDriverParam* driver_param = new LLDriverParam( this );
- if (driver_param->setInfo(info))
- {
- addVisualParam( driver_param );
- LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam;
- if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false))
- {
- llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl;
- continue;
- }
- }
- else
- {
- delete driver_param;
- llwarns << "avatar file: driver_param->parseData() failed" << llendl;
- return FALSE;
- }
- }
-
- // Uncomment to enable avatar_lad.xml debugging.
- std::ofstream file;
- file.open("avatar_lad.log");
- for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*) getNextVisualParam() )
- {
- param->getInfo()->toStream(file);
- file << std::endl;
- }
-
- file.close();
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// loadSkeletonNode(): loads <skeleton> node from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::loadSkeletonNode ()
-{
- mRoot.addChild( &mSkeleton[0] );
-
- for (std::vector<LLViewerJoint *>::iterator iter = mMeshLOD.begin();
- iter != mMeshLOD.end();
- ++iter)
- {
- LLViewerJoint *joint = (LLViewerJoint *) *iter;
- joint->mUpdateXform = FALSE;
- joint->setMeshesToChildren();
- }
-
- mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
- mRoot.addChild(mMeshLOD[MESH_ID_EYELASH]);
- mRoot.addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
- mRoot.addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
- mRoot.addChild(mMeshLOD[MESH_ID_SKIRT]);
- mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
-
- LLViewerJoint *skull = (LLViewerJoint*)mRoot.findJoint("mSkull");
- if (skull)
- {
- skull->addChild(mMeshLOD[MESH_ID_HAIR] );
- }
-
- LLViewerJoint *eyeL = (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
- if (eyeL)
- {
- eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
- }
-
- LLViewerJoint *eyeR = (LLViewerJoint*)mRoot.findJoint("mEyeRight");
- if (eyeR)
- {
- eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
- }
-
- // SKELETAL DISTORTIONS
- {
- LLVOAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter;
- for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin();
- iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end();
- ++iter)
- {
- LLPolySkeletalDistortionInfo *info = *iter;
- LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
- if (!param->setInfo(info))
- {
- delete param;
- return FALSE;
- }
- else
- {
- addVisualParam(param);
- }
- }
- }
-
- // ATTACHMENTS
- {
- LLVOAvatarXmlInfo::attachment_info_list_t::iterator iter;
- for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
- iter != sAvatarXmlInfo->mAttachmentInfoList.end();
- ++iter)
- {
- LLVOAvatarXmlInfo::LLVOAvatarAttachmentInfo *info = *iter;
- if (!isSelf() && info->mJointName == "mScreen")
- { //don't process screen joint for other avatars
- continue;
- }
-
- LLViewerJointAttachment* attachment = new LLViewerJointAttachment();
-
- attachment->setName(info->mName);
- LLJoint *parentJoint = getJoint(info->mJointName);
- if (!parentJoint)
- {
- llwarns << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << llendl;
- delete attachment;
- continue;
- }
-
- if (info->mHasPosition)
- {
- attachment->setOriginalPosition(info->mPosition);
- }
-
- if (info->mHasRotation)
- {
- LLQuaternion rotation;
- rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
- info->mRotationEuler.mV[VY] * DEG_TO_RAD,
- info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
- attachment->setRotation(rotation);
- }
-
- int group = info->mGroup;
- if (group >= 0)
- {
- if (group < 0 || group >= 9)
- {
- llwarns << "Invalid group number (" << group << ") for attachment point " << info->mName << llendl;
- }
- else
- {
- attachment->setGroup(group);
- }
- }
-
- S32 attachmentID = info->mAttachmentID;
- if (attachmentID < 1 || attachmentID > 255)
- {
- llwarns << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << llendl;
- delete attachment;
- continue;
- }
- if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end())
- {
- llwarns << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << llendl;
- delete attachment;
- continue;
- }
-
- attachment->setPieSlice(info->mPieMenuSlice);
- attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
- attachment->setIsHUDAttachment(info->mIsHUDAttachment);
-
- mAttachmentPoints[attachmentID] = attachment;
-
- // now add attachment joint
- parentJoint->addChild(attachment);
- }
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// loadMeshNodes(): loads <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::loadMeshNodes()
-{
- for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin();
- meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end();
- ++meshinfo_iter)
- {
- const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter;
- const std::string &type = info->mType;
- S32 lod = info->mLOD;
-
- LLViewerJointMesh* mesh = NULL;
- U8 mesh_id = 0;
- BOOL found_mesh_id = FALSE;
-
- /* if (type == "hairMesh")
- switch(lod)
- case 0:
- mesh = &mHairMesh0; */
- for (LLVOAvatarDictionary::Meshes::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
- mesh_iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
- ++mesh_iter)
- {
- const EMeshIndex mesh_index = mesh_iter->first;
- const LLVOAvatarDictionary::MeshEntry *mesh_dict = mesh_iter->second;
- if (type.compare(mesh_dict->mName) == 0)
- {
- mesh_id = mesh_index;
- found_mesh_id = TRUE;
- break;
- }
- }
-
- if (found_mesh_id)
- {
- if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
- {
- mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
- }
- else
- {
- llwarns << "Avatar file: <mesh> has invalid lod setting " << lod << llendl;
- return FALSE;
- }
- }
- else
- {
- llwarns << "Ignoring unrecognized mesh type: " << type << llendl;
- return FALSE;
- }
-
- // llinfos << "Parsing mesh data for " << type << "..." << llendl;
-
- // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
- // Do not touch!!!
- mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f );
-
- LLPolyMesh *poly_mesh = NULL;
-
- if (!info->mReferenceMeshName.empty())
- {
- polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName);
- if (polymesh_iter != mMeshes.end())
- {
- poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
- poly_mesh->setAvatar(this);
- }
- else
- {
- // This should never happen
- LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
- }
- }
- else
- {
- poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
- poly_mesh->setAvatar(this);
- }
-
- if( !poly_mesh )
- {
- llwarns << "Failed to load mesh of type " << type << llendl;
- return FALSE;
- }
-
- // Multimap insert
- mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
-
- mesh->setMesh( poly_mesh );
- mesh->setLOD( info->mMinPixelArea );
-
- for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin();
- xmlinfo_iter != info->mPolyMorphTargetInfoList.end();
- ++xmlinfo_iter)
- {
- const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter);
- LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
- if (!param->setInfo(info_pair->first))
- {
- delete param;
- return FALSE;
- }
- else
- {
- if (info_pair->second)
- {
- addSharedVisualParam(param);
- }
- else
- {
- addVisualParam(param);
- }
- }
- }
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// loadLayerSets()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::loadLayersets()
-{
- BOOL success = TRUE;
- for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin();
- layerset_iter != sAvatarXmlInfo->mLayerInfoList.end();
- ++layerset_iter)
- {
- // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
- LLTexLayerSetInfo *layerset_info = *layerset_iter;
- layerset_info->createVisualParams(this);
- }
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// updateVisualParams()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateVisualParams()
-{
- if (gNoRender)
- {
- return;
- }
-
- setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE );
-
- LLCharacter::updateVisualParams();
-
- if (mLastSkeletonSerialNum != mSkeletonSerialNum)
- {
- computeBodySize();
- mLastSkeletonSerialNum = mSkeletonSerialNum;
- mRoot.updateWorldMatrixChildren();
- }
-
- dirtyMesh();
- updateHeadOffset();
-}
-
-//-----------------------------------------------------------------------------
-// isActive()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::isActive() const
-{
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// setPixelAreaAndAngle()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
-{
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
- if (mDrawable.isNull())
- {
- return;
- }
-
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- LLVector4a center;
- center.setAdd(ext[1], ext[0]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(ext[1], ext[0]);
- size.mul(0.5f);
-
- mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
-
- F32 range = mDrawable->mDistanceWRTCamera;
-
- if (range < 0.001f) // range == zero
- {
- mAppAngle = 180.f;
- }
- else
- {
- F32 radius = size.getLength3().getF32();
- mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG;
- }
-
- // We always want to look good to ourselves
- if( isSelf() )
- {
- mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) );
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateJointLODs()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::updateJointLODs()
-{
- const F32 MAX_PIXEL_AREA = 100000000.f;
- F32 lod_factor = (sLODFactor * AVATAR_LOD_TWEAK_RANGE + (1.f - AVATAR_LOD_TWEAK_RANGE));
- F32 avatar_num_min_factor = clamp_rescale(sLODFactor, 0.f, 1.f, 0.25f, 0.6f);
- F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor);
- F32 area_scale = 0.16f;
-
- {
- if (isSelf())
- {
- if(gAgentCamera.cameraCustomizeAvatar() || gAgentCamera.cameraMouselook())
- {
- mAdjustedPixelArea = MAX_PIXEL_AREA;
- }
- else
- {
- mAdjustedPixelArea = mPixelArea*area_scale;
- }
- }
- else if (mIsDummy)
- {
- mAdjustedPixelArea = MAX_PIXEL_AREA;
- }
- else
- {
- // reported avatar pixel area is dependent on avatar render load, based on number of visible avatars
- mAdjustedPixelArea = (F32)mPixelArea * area_scale * lod_factor * lod_factor * avatar_num_factor * avatar_num_factor;
- }
-
- // now select meshes to render based on adjusted pixel area
- BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE);
- if (res)
- {
- sNumLODChangesThisFrame++;
- dirtyMesh(2);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// createDrawable()
-//-----------------------------------------------------------------------------
-LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline)
-{
- pipeline->allocDrawable(this);
- mDrawable->setLit(FALSE);
-
- LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR);
-
- // Only a single face (one per avatar)
- //this face will be splitted into several if its vertex buffer is too long.
- mDrawable->setState(LLDrawable::ACTIVE);
- mDrawable->addFace(poolp, NULL);
- mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR);
-
- mNumInitFaces = mDrawable->getNumFaces() ;
-
- dirtyMesh(2);
- return mDrawable;
-}
-
-
-void LLVOAvatar::updateGL()
-{
- if (mMeshTexturesDirty)
- {
- updateMeshTextures();
- mMeshTexturesDirty = FALSE;
- }
-}
-
-//-----------------------------------------------------------------------------
-// updateGeometry()
-//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar");
-BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
-{
- LLFastTimer ftm(FTM_UPDATE_AVATAR);
- if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
- {
- return TRUE;
- }
-
- if (!mMeshValid)
- {
- return TRUE;
- }
-
- if (!drawable)
- {
- llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl;
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// updateSexDependentLayerSets()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake )
-{
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
-}
-
-//-----------------------------------------------------------------------------
-// dirtyMesh()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::dirtyMesh()
-{
- dirtyMesh(1);
-}
-void LLVOAvatar::dirtyMesh(S32 priority)
-{
- mDirtyMesh = llmax(mDirtyMesh, priority);
-}
-//-----------------------------------------------------------------------------
-// hideSkirt()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::hideSkirt()
-{
- mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE);
-}
-
-BOOL LLVOAvatar::setParent(LLViewerObject* parent)
-{
- BOOL ret ;
- if (parent == NULL)
- {
- getOffObject();
- ret = LLViewerObject::setParent(parent);
- if (isSelf())
- {
- gAgentCamera.resetCamera();
- }
- }
- else
- {
- ret = LLViewerObject::setParent(parent);
- if(ret)
- {
- sitOnObject(parent);
- }
- }
- return ret ;
-}
-
-void LLVOAvatar::addChild(LLViewerObject *childp)
-{
- childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
- LLViewerObject::addChild(childp);
- if (childp->mDrawable)
- {
- attachObject(childp);
- }
- else
- {
- mPendingAttachment.push_back(childp);
- }
-}
-
-void LLVOAvatar::removeChild(LLViewerObject *childp)
-{
- LLViewerObject::removeChild(childp);
- if (!detachObject(childp))
- {
- llwarns << "Calling detach on non-attached object " << llendl;
- }
-}
-
-LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
-{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
-
- // This should never happen unless the server didn't process the attachment point
- // correctly, but putting this check in here to be safe.
- if (attachmentID & ATTACHMENT_ADD)
- {
- llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;
- attachmentID &= ~ATTACHMENT_ADD;
- }
-
- LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
-
- if (!attachment)
- {
- llwarns << "Object attachment point invalid: " << attachmentID << llendl;
- attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest)
- }
-
- return attachment;
-}
-
-//-----------------------------------------------------------------------------
-// attachObject()
-//-----------------------------------------------------------------------------
-const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)
-{
- LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object);
-
- if (!attachment || !attachment->addObject(viewer_object))
- {
- return 0;
- }
-
- if (viewer_object->isSelected())
- {
- LLSelectMgr::getInstance()->updateSelectionCenter();
- LLSelectMgr::getInstance()->updatePointAt();
- }
-
- return attachment;
-}
-
-//-----------------------------------------------------------------------------
-// attachObject()
-//-----------------------------------------------------------------------------
-U32 LLVOAvatar::getNumAttachments() const
-{
- U32 num_attachments = 0;
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- const LLViewerJointAttachment *attachment_pt = (*iter).second;
- num_attachments += attachment_pt->getNumObjects();
- }
- return num_attachments;
-}
-
-//-----------------------------------------------------------------------------
-// canAttachMoreObjects()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects() const
-{
- return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
-}
-
-//-----------------------------------------------------------------------------
-// canAttachMoreObjects()
-// Returns true if we can attach <n> more objects.
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
-{
- return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
-}
-
-//-----------------------------------------------------------------------------
-// lazyAttach()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::lazyAttach()
-{
- std::vector<LLPointer<LLViewerObject> > still_pending;
-
- for (U32 i = 0; i < mPendingAttachment.size(); i++)
- {
- if (mPendingAttachment[i]->mDrawable)
- {
- attachObject(mPendingAttachment[i]);
- }
- else
- {
- still_pending.push_back(mPendingAttachment[i]);
- }
- }
-
- mPendingAttachment = still_pending;
-}
-
-void LLVOAvatar::resetHUDAttachments()
-{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getIsHUDAttachment())
- {
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && attached_object->mDrawable.notNull())
- {
- gPipeline.markMoved(attached_object->mDrawable);
- }
- }
- }
- }
-}
-
-void LLVOAvatar::rebuildRiggedAttachments( void )
-{
- for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
- {
- LLViewerJointAttachment* pAttachment = iter->second;
- LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end();
-
- for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin();
- attachmentIter != attachmentIterEnd; ++attachmentIter)
- {
- const LLViewerObject* pAttachedObject = *attachmentIter;
- if ( pAttachment && pAttachedObject->mDrawable.notNull() )
- {
- gPipeline.markRebuild(pAttachedObject->mDrawable);
- }
- }
- }
-}
-//-----------------------------------------------------------------------------
-// cleanupAttachedMesh()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
-{
- //If a VO has a skin that we'll reset the joint positions to their default
- if ( pVO && pVO->mDrawable )
- {
- LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
- if ( pVObj )
- {
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID() );
- if ( pSkinData )
- {
- const int jointCnt = pSkinData->mJointNames.size();
- bool fullRig = ( jointCnt>=20 ) ? true : false;
- if ( fullRig )
- {
- const int bindCnt = pSkinData->mAlternateBindMatrix.size();
- if ( bindCnt > 0 )
- {
- LLVOAvatar::resetJointPositionsToDefault();
- }
- }
- }
- }
- }
-}
-//-----------------------------------------------------------------------------
-// detachObject()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
-{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
-
- if (attachment->isObjectAttached(viewer_object))
- {
- cleanupAttachedMesh( viewer_object );
- attachment->removeObject(viewer_object);
- lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;
- return TRUE;
- }
- }
-
- std::vector<LLPointer<LLViewerObject> >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object);
- if (iter != mPendingAttachment.end())
- {
- mPendingAttachment.erase(iter);
- return TRUE;
- }
-
- return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// sitDown()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::sitDown(BOOL bSitting)
-{
- mIsSitting = bSitting;
- if (isSelf())
- {
- // Update Movement Controls according to own Sitting mode
- LLFloaterMove::setSittingMode(bSitting);
- }
-}
-
-//-----------------------------------------------------------------------------
-// sitOnObject()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
-{
- if (isSelf())
- {
- // Might be first sit
- //LLFirstUse::useSit();
-
- gAgent.setFlying(FALSE);
- gAgentCamera.setThirdPersonHeadOffset(LLVector3::zero);
- //interpolate to new camera position
- gAgentCamera.startCameraAnimation();
- // make sure we are not trying to autopilot
- gAgent.stopAutoPilot();
- gAgentCamera.setupSitCamera();
- if (gAgentCamera.getForceMouselook())
- {
- gAgentCamera.changeCameraToMouselook();
- }
- }
-
- if (mDrawable.isNull())
- {
- return;
- }
- LLQuaternion inv_obj_rot = ~sit_object->getRenderRotation();
- LLVector3 obj_pos = sit_object->getRenderPosition();
-
- LLVector3 rel_pos = getRenderPosition() - obj_pos;
- rel_pos.rotVec(inv_obj_rot);
-
- mDrawable->mXform.setPosition(rel_pos);
- mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot);
-
- gPipeline.markMoved(mDrawable, TRUE);
- // Notice that removing sitDown() from here causes avatars sitting on
- // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
- sitDown(TRUE);
- mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
- mRoot.setPosition(getPosition());
- mRoot.updateWorldMatrixChildren();
-
- stopMotion(ANIM_AGENT_BODY_NOISE);
-
-}
-
-//-----------------------------------------------------------------------------
-// getOffObject()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::getOffObject()
-{
- if (mDrawable.isNull())
- {
- return;
- }
-
- LLViewerObject* sit_object = (LLViewerObject*)getParent();
-
- if (sit_object)
- {
- stopMotionFromSource(sit_object->getID());
- LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
-
- LLViewerObject::const_child_list_t& child_list = sit_object->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); ++iter)
- {
- LLViewerObject* child_objectp = *iter;
-
- stopMotionFromSource(child_objectp->getID());
- LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE);
- }
- }
-
- // assumes that transform will not be updated with drawable still having a parent
- LLVector3 cur_position_world = mDrawable->getWorldPosition();
- LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
-
- // set *local* position based on last *world* position, since we're unparenting the avatar
- mDrawable->mXform.setPosition(cur_position_world);
- mDrawable->mXform.setRotation(cur_rotation_world);
-
- gPipeline.markMoved(mDrawable, TRUE);
-
- sitDown(FALSE);
-
- mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject
- mRoot.setPosition(cur_position_world);
- mRoot.setRotation(cur_rotation_world);
- mRoot.getXform()->update();
-
- startMotion(ANIM_AGENT_BODY_NOISE);
-
- if (isSelf())
- {
- LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion();
- LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT;
- av_rot = av_rot * obj_rot;
- LLVector3 at_axis = LLVector3::x_axis;
- at_axis = at_axis * av_rot;
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- gAgent.resetAxes(at_axis);
-
- //reset orientation
-// mRoot.setRotation(avWorldRot);
- gAgentCamera.setThirdPersonHeadOffset(LLVector3(0.f, 0.f, 1.f));
-
- gAgentCamera.setSitCamera(LLUUID::null);
- }
-}
-
-//-----------------------------------------------------------------------------
-// findAvatarFromAttachment()
-//-----------------------------------------------------------------------------
-// static
-LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj )
-{
- if( obj->isAttachment() )
- {
- do
- {
- obj = (LLViewerObject*) obj->getParent();
- }
- while( obj && !obj->isAvatar() );
-
- if( obj && !obj->isDead() )
- {
- return (LLVOAvatar*)obj;
- }
- }
- return NULL;
-}
-
-// warning: order(N) not order(1)
-S32 LLVOAvatar::getAttachmentCount()
-{
- S32 count = mAttachmentPoints.size();
- return count;
-}
-
-LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const
-{
- if (color_name=="skin_color" && mTexSkinColor)
- {
- return mTexSkinColor->getColor();
- }
- else if(color_name=="hair_color" && mTexHairColor)
- {
- return mTexHairColor->getColor();
- }
- if(color_name=="eye_color" && mTexEyeColor)
- {
- return mTexEyeColor->getColor();
- }
- else
- {
-// return LLColor4( .5f, .5f, .5f, .5f );
- return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color
- }
-}
-
-// virtual
-void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )
-{
-}
-
-void LLVOAvatar::invalidateAll()
-{
-}
-
-void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake )
-{
- if (global_color == mTexSkinColor)
- {
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
- }
- else if (global_color == mTexHairColor)
- {
- invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
- invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake );
-
- // ! BACKWARDS COMPATIBILITY !
- // Fix for dealing with avatars from viewers that don't bake hair.
- if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex))
- {
- LLColor4 color = mTexHairColor->getColor();
- for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
- {
- mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] );
- }
- }
- }
- else if (global_color == mTexEyeColor)
- {
-// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl;
- invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake );
- }
- updateMeshTextures();
-}
-
-BOOL LLVOAvatar::isVisible() const
-{
- return mDrawable.notNull()
- && (mDrawable->isVisible() || mIsDummy);
-}
-
-// Determine if we have enough avatar data to render
-BOOL LLVOAvatar::getIsCloud()
-{
- // Do we have a shape?
- if (visualParamWeightsAreDefault())
- {
- return TRUE;
- }
-
- if (!isTextureDefined(TEX_LOWER_BAKED) ||
- !isTextureDefined(TEX_UPPER_BAKED) ||
- !isTextureDefined(TEX_HEAD_BAKED))
- {
- return TRUE;
- }
- return FALSE;
-}
-
-// call periodically to keep isFullyLoaded up to date.
-// returns true if the value has changed.
-BOOL LLVOAvatar::updateIsFullyLoaded()
-{
- const BOOL loading = getIsCloud();
- updateRuthTimer(loading);
- return processFullyLoadedChange(loading);
-}
-
-void LLVOAvatar::updateRuthTimer(bool loading)
-{
- if (isSelf() || !loading)
- {
- return;
- }
-
- if (mPreviousFullyLoaded)
- {
- mRuthTimer.reset();
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl;
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezCloudNotification",args);
- }
- mRuthDebugTimer.reset();
- }
-
- const F32 LOADING_TIMEOUT__SECONDS = 120.f;
- if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS)
- {
- llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' "
- << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) "
- << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) "
- << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) "
- << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )."
- << llendl;
-
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
- mRuthTimer.reset();
- }
-}
-
-BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
-{
- // we wait a little bit before giving the all clear,
- // to let textures settle down
- const F32 PAUSE = 1.f;
- if (loading)
- mFullyLoadedTimer.reset();
-
- mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE);
-
- if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
- {
- if (!mPreviousFullyLoaded && !loading && mFullyLoaded)
- {
- llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl;
- LLSD args;
- args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
- args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
- args["NAME"] = getFullname();
- LLNotificationsUtil::add("AvatarRezNotification",args);
- }
- }
-
- // did our loading state "change" from last call?
- const S32 UPDATE_RATE = 30;
- BOOL changed =
- ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call
- (!mFullyLoadedInitialized) || // if we've never been called before
- (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change
-
- mPreviousFullyLoaded = mFullyLoaded;
- mFullyLoadedInitialized = TRUE;
- mFullyLoadedFrameCounter++;
-
- return changed;
-}
-
-BOOL LLVOAvatar::isFullyLoaded() const
-{
- if (gSavedSettings.getBOOL("RenderUnloadedAvatar"))
- return TRUE;
- else
- return mFullyLoaded;
-}
-
-
-//-----------------------------------------------------------------------------
-// findMotion()
-//-----------------------------------------------------------------------------
-LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const
-{
- return mMotionController.findMotion(id);
-}
-
-//-----------------------------------------------------------------------------
-// updateMeshTextures()
-// Uses the current TE values to set the meshes' and layersets' textures.
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateMeshTextures()
-{
- // llinfos << "updateMeshTextures" << llendl;
- if (gNoRender) return;
-
- // if user has never specified a texture, assign the default
- for (U32 i=0; i < getNumTEs(); i++)
- {
- const LLViewerTexture* te_image = getImage(i, 0);
- if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT))
- {
- setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR), 0); // IMG_DEFAULT_AVATAR = a special texture that's never rendered.
- }
- }
-
- const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures
- const BOOL other_culled = !isSelf() && mCulled;
- LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
- BOOL paused = FALSE;
- if(!isSelf())
- {
- src_callback_list = &mCallbackTextureList ;
- paused = mLoadedCallbacksPaused ;
- }
-
- std::vector<BOOL> is_layer_baked;
- is_layer_baked.resize(mBakedTextureDatas.size(), false);
-
- std::vector<BOOL> use_lkg_baked_layer; // lkg = "last known good"
- use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false);
-
- for (U32 i=0; i < mBakedTextureDatas.size(); i++)
- {
- is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
-
- if (!other_culled)
- {
- // When an avatar is changing clothes and not in Appearance mode,
- // use the last-known good baked texture until it finish the first
- // render of the new layerset.
- const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet
- && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()
- || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() );
- use_lkg_baked_layer[i] = (!is_layer_baked[i]
- && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR)
- && layerset_invalid);
- if (use_lkg_baked_layer[i])
- {
- mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE);
- }
- }
- else
- {
- use_lkg_baked_layer[i] = (!is_layer_baked[i]
- && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR);
- if (mBakedTextureDatas[i].mTexLayerSet)
- {
- mBakedTextureDatas[i].mTexLayerSet->destroyComposite();
- }
- }
-
- }
-
- // Turn on alpha masking correctly for yourself and other avatars on 1.23+
- mSupportsAlphaLayers = isSelf() || is_layer_baked[BAKED_HAIR];
-
- // Baked textures should be requested from the sim this avatar is on. JC
- const LLHost target_host = getObjectHost();
- if (!target_host.isOk())
- {
- llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl;
- }
-
- for (U32 i=0; i < mBakedTextureDatas.size(); i++)
- {
- if (use_lkg_baked_layer[i] && !self_customizing )
- {
- LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host );
- mBakedTextureDatas[i].mIsUsed = TRUE;
- for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
- {
- mBakedTextureDatas[i].mMeshes[k]->setTexture( baked_img );
- }
- }
- else if (!self_customizing && is_layer_baked[i])
- {
- LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
- if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex )
- {
- // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing).
- useBakedTexture( baked_img->getID() );
- }
- else
- {
- mBakedTextureDatas[i].mIsLoaded = FALSE;
- if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
- {
- baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ),
- src_callback_list, paused);
- }
- baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),
- src_callback_list, paused );
- }
- }
- else if (mBakedTextureDatas[i].mTexLayerSet
- && !other_culled)
- {
- mBakedTextureDatas[i].mTexLayerSet->createComposite();
- mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE );
- mBakedTextureDatas[i].mIsUsed = FALSE;
- for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
- {
- mBakedTextureDatas[i].mMeshes[k]->setLayerSet( mBakedTextureDatas[i].mTexLayerSet );
- }
- }
- }
-
- // set texture and color of hair manually if we are not using a baked image.
- // This can happen while loading hair for yourself, or for clients that did not
- // bake a hair texture. Still needed for yourself after 1.22 is depricated.
- if (!is_layer_baked[BAKED_HAIR] || self_customizing)
- {
- const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1);
- LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 );
- for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
- {
- mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] );
- mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img );
- }
- }
-
-
- for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
- baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
- ++baked_iter)
- {
- const EBakedTextureIndex baked_index = baked_iter->first;
- const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second;
-
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex texture_index = *local_tex_iter;
- const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled;
- if (isSelf())
- {
- setBakedReady(texture_index, is_baked_ready);
- }
- }
- }
- removeMissingBakedTextures();
-}
-
-// virtual
-//-----------------------------------------------------------------------------
-// setLocalTexture()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index )
-{
- // invalid for anyone but self
- llassert(0);
-}
-
-//virtual
-void LLVOAvatar::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index)
-{
- // invalid for anyone but self
- llassert(0);
-}
-
-void LLVOAvatar::addChat(const LLChat& chat)
-{
- std::deque<LLChat>::iterator chat_iter;
-
- mChats.push_back(chat);
-
- S32 chat_length = 0;
- for( chat_iter = mChats.begin(); chat_iter != mChats.end(); ++chat_iter)
- {
- chat_length += chat_iter->mText.size();
- }
-
- // remove any excess chat
- chat_iter = mChats.begin();
- while ((chat_length > MAX_BUBBLE_CHAT_LENGTH || mChats.size() > MAX_BUBBLE_CHAT_UTTERANCES) && chat_iter != mChats.end())
- {
- chat_length -= chat_iter->mText.size();
- mChats.pop_front();
- chat_iter = mChats.begin();
- }
-
- mChatTimer.reset();
-}
-
-void LLVOAvatar::clearChat()
-{
- mChats.clear();
-}
-
-// adds a morph mask to the appropriate baked texture structure
-void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer)
-{
- if (index < BAKED_NUM_INDICES)
- {
- LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer);
- mBakedTextureDatas[index].mMaskedMorphs.push_front(morph);
- }
-}
-
-// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise
-BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index)
-{
- if (index >= BAKED_NUM_INDICES)
- {
- return FALSE;
- }
-
- if (!mBakedTextureDatas[index].mMaskedMorphs.empty())
- {
- if (isSelf())
- {
- LLTexLayerSet *layer_set = mBakedTextureDatas[index].mTexLayerSet;
- if (layer_set)
- {
- return !layer_set->isMorphValid();
- }
- }
- else
- {
- return FALSE;
- }
- }
-
- return FALSE;
-}
-
-void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index)
-{
- if (index >= BAKED_NUM_INDICES)
- {
- llwarns << "invalid baked texture index passed to applyMorphMask" << llendl;
- return;
- }
-
- for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin();
- iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter)
- {
- const LLMaskedMorph* maskedMorph = (*iter);
- maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// releaseComponentTextures()
-// release any component texture UUIDs for which we have a baked texture
-// ! BACKWARDS COMPATIBILITY !
-// This is only called for non-self avatars, it can be taken out once component
-// textures aren't communicated by non-self avatars.
-//-----------------------------------------------------------------------------
-void LLVOAvatar::releaseComponentTextures()
-{
- // ! BACKWARDS COMPATIBILITY !
- // Detect if the baked hair texture actually wasn't sent, and if so set to default
- if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED,0)->getID() == getImage(TEX_SKIRT_BAKED,0)->getID())
- {
- if (getImage(TEX_HAIR_BAKED,0)->getID() != IMG_INVISIBLE)
- {
- // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default
- setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR);
- }
- }
-
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID
- if (!isTextureDefined(bakedDicEntry->mTextureIndex)
- && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ))
- {
- continue;
- }
-
- for (U8 texture = 0; texture < bakedDicEntry->mLocalTextures.size(); texture++)
- {
- const U8 te = (ETextureIndex)bakedDicEntry->mLocalTextures[texture];
- setTETexture(te, IMG_DEFAULT_AVATAR);
- }
- }
-}
-
-//static
-BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name )
-{
- switch( te )
- {
- case TEX_UPPER_SHIRT:
- param_name[0] = 803; //"shirt_red";
- param_name[1] = 804; //"shirt_green";
- param_name[2] = 805; //"shirt_blue";
- break;
-
- case TEX_LOWER_PANTS:
- param_name[0] = 806; //"pants_red";
- param_name[1] = 807; //"pants_green";
- param_name[2] = 808; //"pants_blue";
- break;
-
- case TEX_LOWER_SHOES:
- param_name[0] = 812; //"shoes_red";
- param_name[1] = 813; //"shoes_green";
- param_name[2] = 817; //"shoes_blue";
- break;
-
- case TEX_LOWER_SOCKS:
- param_name[0] = 818; //"socks_red";
- param_name[1] = 819; //"socks_green";
- param_name[2] = 820; //"socks_blue";
- break;
-
- case TEX_UPPER_JACKET:
- case TEX_LOWER_JACKET:
- param_name[0] = 834; //"jacket_red";
- param_name[1] = 835; //"jacket_green";
- param_name[2] = 836; //"jacket_blue";
- break;
-
- case TEX_UPPER_GLOVES:
- param_name[0] = 827; //"gloves_red";
- param_name[1] = 829; //"gloves_green";
- param_name[2] = 830; //"gloves_blue";
- break;
-
- case TEX_UPPER_UNDERSHIRT:
- param_name[0] = 821; //"undershirt_red";
- param_name[1] = 822; //"undershirt_green";
- param_name[2] = 823; //"undershirt_blue";
- break;
-
- case TEX_LOWER_UNDERPANTS:
- param_name[0] = 824; //"underpants_red";
- param_name[1] = 825; //"underpants_green";
- param_name[2] = 826; //"underpants_blue";
- break;
-
- case TEX_SKIRT:
- param_name[0] = 921; //"skirt_red";
- param_name[1] = 922; //"skirt_green";
- param_name[2] = 923; //"skirt_blue";
- break;
-
- case TEX_HEAD_TATTOO:
- case TEX_LOWER_TATTOO:
- case TEX_UPPER_TATTOO:
- param_name[0] = 1071; //"tattoo_red";
- param_name[1] = 1072; //"tattoo_green";
- param_name[2] = 1073; //"tattoo_blue";
- break;
-
- default:
- llassert(0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake )
-{
- U32 param_name[3];
- if( teToColorParams( te, param_name ) )
- {
- setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake );
- setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake );
- setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake );
- }
-}
-
-LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te )
-{
- LLColor4 color;
- U32 param_name[3];
- if( teToColorParams( te, param_name ) )
- {
- color.mV[VX] = getVisualParamWeight( param_name[0] );
- color.mV[VY] = getVisualParamWeight( param_name[1] );
- color.mV[VZ] = getVisualParamWeight( param_name[2] );
- }
- return color;
-}
-
-// static
-LLColor4 LLVOAvatar::getDummyColor()
-{
- return DUMMY_COLOR;
-}
-
-void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const
-{
- llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl;
- for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
- iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
- ++iter)
- {
- const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
- // TODO: MULTI-WEARABLE: handle multiple textures for self
- const LLViewerTexture* te_image = getImage(iter->first,0);
- if( !te_image )
- {
- llinfos << " " << texture_dict->mName << ": null ptr" << llendl;
- }
- else if( te_image->getID().isNull() )
- {
- llinfos << " " << texture_dict->mName << ": null UUID" << llendl;
- }
- else if( te_image->getID() == IMG_DEFAULT )
- {
- llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl;
- }
- else if( te_image->getID() == IMG_DEFAULT_AVATAR )
- {
- llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl;
- }
- else
- {
- llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl;
- }
- }
-}
-
-// Unlike most wearable functions, this works for both self and other.
-BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
-{
- if (mIsDummy) return TRUE;
-
- switch(type)
- {
- case LLWearableType::WT_SHAPE:
- case LLWearableType::WT_SKIN:
- case LLWearableType::WT_HAIR:
- case LLWearableType::WT_EYES:
- return TRUE; // everyone has all bodyparts
- default:
- break; // Do nothing
- }
-
- /* switch(type)
- case LLWearableType::WT_SHIRT:
- indicator_te = TEX_UPPER_SHIRT; */
- for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
- tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
- ++tex_iter)
- {
- const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second;
- if (texture_dict->mWearableType == type)
- {
- // If you're checking another avatar's clothing, you don't have component textures.
- // Thus, you must check to see if the corresponding baked texture is defined.
- // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
- // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
- // gets baked into a texture that always exists (upper or lower).
- if (texture_dict->mIsUsedByBakedTexture)
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
- }
- return FALSE;
- }
- }
- return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-// clampAttachmentPositions()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::clampAttachmentPositions()
-{
- if (isDead())
- {
- return;
- }
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment)
- {
- attachment->clampObjectPosition();
- }
- }
-}
-
-BOOL LLVOAvatar::hasHUDAttachment() const
-{
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0)
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-LLBBox LLVOAvatar::getHUDBBox() const
-{
- LLBBox bbox;
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getIsHUDAttachment())
- {
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object == NULL)
- {
- llwarns << "HUD attached object is NULL!" << llendl;
- continue;
- }
- // initialize bounding box to contain identity orientation and center point for attached object
- bbox.addPointLocal(attached_object->getPosition());
- // add rotated bounding box for attached object
- bbox.addBBoxAgent(attached_object->getBoundingBoxAgent());
- LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end();
- ++iter)
- {
- const LLViewerObject* child_objectp = *iter;
- bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent());
- }
- }
- }
- }
-
- return bbox;
-}
-
-void LLVOAvatar::rebuildHUD()
-{
-}
-
-//-----------------------------------------------------------------------------
-// onFirstTEMessageReceived()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::onFirstTEMessageReceived()
-{
- if( !mFirstTEMessageReceived )
- {
- mFirstTEMessageReceived = TRUE;
-
- LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
- BOOL paused = FALSE ;
- if(!isSelf())
- {
- src_callback_list = &mCallbackTextureList ;
- paused = mLoadedCallbacksPaused ;
- }
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
-
- // Use any baked textures that we have even if they haven't downloaded yet.
- // (That is, don't do a transition from unbaked to baked.)
- if (layer_baked)
- {
- LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
- mBakedTextureDatas[i].mLastTextureIndex = image->getID();
- // If we have more than one texture for the other baked layers, we'll want to call this for them too.
- if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
- {
- image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ),
- src_callback_list, paused);
- }
- image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),
- src_callback_list, paused );
- }
- }
-
- mMeshTexturesDirty = TRUE;
- gPipeline.markGLRebuild(this);
- }
-}
-
-//-----------------------------------------------------------------------------
-// bool visualParamWeightsAreDefault()
-//-----------------------------------------------------------------------------
-bool LLVOAvatar::visualParamWeightsAreDefault()
-{
- bool rtn = true;
-
- bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT);
- for (LLVisualParam *param = getFirstVisualParam();
- param;
- param = getNextVisualParam())
- {
- if (param->isTweakable())
- {
- LLViewerVisualParam* vparam = dynamic_cast<LLViewerVisualParam*>(param);
- llassert(vparam);
- bool is_skirt_param = vparam &&
- LLWearableType::WT_SKIRT == vparam->getWearableType();
- if (param->getWeight() != param->getDefaultWeight() &&
- // we have to not care whether skirt weights are default, if we're not actually wearing a skirt
- (is_wearing_skirt || !is_skirt_param))
- {
- //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl;
- rtn = false;
- break;
- }
- }
- }
-
- //llinfos << "params are default ? " << int(rtn) << llendl;
-
- return rtn;
-}
-
-
-//-----------------------------------------------------------------------------
-// processAvatarAppearance()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
-{
- if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
- {
- llwarns << "Blocking AvatarAppearance message" << llendl;
- return;
- }
-
- LLMemType mt(LLMemType::MTYPE_AVATAR);
-
-// llinfos << "processAvatarAppearance start " << mID << llendl;
- BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
-
- mFirstAppearanceMessageReceived = TRUE;
-
- if( isSelf() )
- {
- llwarns << "Received AvatarAppearance for self" << llendl;
- if( mFirstTEMessageReceived )
- {
-// llinfos << "processAvatarAppearance end " << mID << llendl;
- return;
- }
- }
-
- if (gNoRender)
- {
- return;
- }
-
- ESex old_sex = getSex();
-
-// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl;
-// dumpAvatarTEs( "PRE processAvatarAppearance()" );
- unpackTEMessage(mesgsys, _PREHASH_ObjectData);
-// dumpAvatarTEs( "POST processAvatarAppearance()" );
-
- // prevent the overwriting of valid baked textures with invalid baked textures
- for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++)
- {
- if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex)
- && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT
- && baked_index != BAKED_SKIRT)
- {
- setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,
- LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
- }
- }
-
-
- if( !is_first_appearance_message )
- {
- onFirstTEMessageReceived();
- }
-
- setCompositeUpdatesEnabled( FALSE );
- mMeshTexturesDirty = TRUE;
- gPipeline.markGLRebuild(this);
-
- // ! BACKWARDS COMPATIBILITY !
- // Non-self avatars will no longer have component textures
- if (!isSelf())
- {
- releaseComponentTextures();
- }
-
- // parse visual params
- S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
- bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
- if( num_blocks > 1 && !drop_visual_params_debug)
- {
- BOOL params_changed = FALSE;
- BOOL interp_params = FALSE;
-
- LLVisualParam* param = getFirstVisualParam();
- llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
- if (!param)
- {
- llwarns << "No visual params!" << llendl;
- }
- else
- {
- for( S32 i = 0; i < num_blocks; i++ )
- {
- while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
- {
- param = getNextVisualParam();
- }
-
- if( !param )
- {
- // more visual params supplied than expected - just process what we know about
- break;
- }
-
- U8 value;
- mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i);
- F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight());
-
- if (is_first_appearance_message || (param->getWeight() != newWeight))
- {
- //llinfos << "Received update for param " << param->getDisplayName() << " at value " << newWeight << llendl;
- params_changed = TRUE;
- if(is_first_appearance_message)
- {
- param->setWeight(newWeight, FALSE);
- }
- else
- {
- interp_params = TRUE;
- param->setAnimationTarget(newWeight, FALSE);
- }
- }
- param = getNextVisualParam();
- }
- }
-
- const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
- if (num_blocks != expected_tweakable_count)
- {
- llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
- }
-
- if (params_changed)
- {
- if (interp_params)
- {
- startAppearanceAnimation();
- }
- updateVisualParams();
-
- ESex new_sex = getSex();
- if( old_sex != new_sex )
- {
- updateSexDependentLayerSets( FALSE );
- }
- }
-
- llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) );
- }
- else
- {
- // AvatarAppearance message arrived without visual params
- if (drop_visual_params_debug)
- {
- llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl;
- }
- else
- {
- llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
- }
-
- const F32 LOADING_TIMEOUT_SECONDS = 60.f;
- // this isn't really a problem if we already have a non-default shape
- if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS)
- {
- // re-request appearance, hoping that it comes back with a shape next time
- llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl;
- LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
- mRuthTimer.reset();
- }
- else
- {
- llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl;
- // we don't really care.
- }
- }
-
- setCompositeUpdatesEnabled( TRUE );
-
- // If all of the avatars are completely baked, release the global image caches to conserve memory.
- LLVOAvatar::cullAvatarsByPixelArea();
-
-// llinfos << "processAvatarAppearance end " << mID << llendl;
-}
-
-// static
-void LLVOAvatar::getAnimLabels( LLDynamicArray<std::string>* labels )
-{
- S32 i;
- for( i = 0; i < gUserAnimStatesCount; i++ )
- {
- labels->put( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) );
- }
-
- // Special case to trigger away (AFK) state
- labels->put( "Away From Keyboard" );
-}
-
-// static
-void LLVOAvatar::getAnimNames( LLDynamicArray<std::string>* names )
-{
- S32 i;
-
- for( i = 0; i < gUserAnimStatesCount; i++ )
- {
- names->put( std::string(gUserAnimStates[i].mName) );
- }
-
- // Special case to trigger away (AFK) state
- names->put( "enter_away_from_keyboard_state" );
-}
-
-void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
-{
- if (!userdata) return;
-
- //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl;
- const LLMemType mt(LLMemType::MTYPE_AVATAR);
- const LLUUID id = src_vi->getID();
-
- LLTextureMaskData* maskData = (LLTextureMaskData*) userdata;
- LLVOAvatar* self = (LLVOAvatar*) gObjectList.findObject( maskData->mAvatarID );
-
- // if discard level is 2 less than last discard level we processed, or we hit 0,
- // then generate morph masks
- if(self && success && (discard_level < maskData->mLastDiscardLevel - 2 || discard_level == 0))
- {
- if(aux_src && aux_src->getComponents() == 1)
- {
- if (!aux_src->getData())
- {
- llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl;
- return;
- }
-
- U32 gl_name;
- LLImageGL::generateTextures(1, &gl_name );
- stop_glerror();
-
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
- stop_glerror();
-
- LLImageGL::setManualImage(
- GL_TEXTURE_2D, 0, GL_ALPHA8,
- aux_src->getWidth(), aux_src->getHeight(),
- GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData());
- stop_glerror();
-
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
-
- /* if( id == head_baked->getID() )
- if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet)
- //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl;
- self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1);
- maskData->mLastDiscardLevel = discard_level; */
- BOOL found_texture_id = false;
- for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
- iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
- ++iter)
- {
-
- const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
- if (texture_dict->mIsUsedByBakedTexture)
- {
- const ETextureIndex texture_index = iter->first;
- const LLViewerTexture *baked_img = self->getImage(texture_index, 0);
- if (baked_img && id == baked_img->getID())
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index);
- maskData->mLastDiscardLevel = discard_level;
- if (self->mBakedTextureDatas[baked_index].mMaskTexName)
- {
- LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName));
- }
- self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name;
- found_texture_id = true;
- break;
- }
- }
- }
- if (!found_texture_id)
- {
- llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl;
- }
- self->dirtyMesh();
- }
- else
- {
- // this can happen when someone uses an old baked texture possibly provided by
- // viewer-side baked texture caching
- llwarns << "Masks loaded callback but NO aux source!" << llendl;
- }
- }
-
- if (final || !success)
- {
- delete maskData;
- }
-}
-
-// static
-void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
-{
- LLUUID *avatar_idp = (LLUUID *)userdata;
- LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
-
- if (!success && selfp)
- {
- selfp->removeMissingBakedTextures();
- }
- if (final || !success )
- {
- delete avatar_idp;
- }
-}
-
-void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
-{
- //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl;
-
- LLUUID id = src_vi->getID();
- LLUUID *avatar_idp = (LLUUID *)userdata;
- LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
-
- if (selfp && !success)
- {
- selfp->removeMissingBakedTextures();
- }
-
- if( final || !success )
- {
- delete avatar_idp;
- }
-
- if( selfp && success && final )
- {
- selfp->useBakedTexture( id );
- }
-}
-
-
-// Called when baked texture is loaded and also when we start up with a baked texture
-void LLVOAvatar::useBakedTexture( const LLUUID& id )
-{
- /* if(id == head_baked->getID())
- mHeadBakedLoaded = TRUE;
- mLastHeadBakedID = id;
- mHeadMesh0.setTexture( head_baked );
- mHeadMesh1.setTexture( head_baked ); */
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 );
- if (id == image_baked->getID())
- {
- mBakedTextureDatas[i].mIsLoaded = true;
- mBakedTextureDatas[i].mLastTextureIndex = id;
- mBakedTextureDatas[i].mIsUsed = true;
- for (U32 k = 0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
- {
- mBakedTextureDatas[i].mMeshes[k]->setTexture( image_baked );
- }
- if (mBakedTextureDatas[i].mTexLayerSet)
- {
- //mBakedTextureDatas[i].mTexLayerSet->destroyComposite();
- }
- const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- if (isSelf()) setBakedReady(*local_tex_iter, TRUE);
- }
-
- // ! BACKWARDS COMPATIBILITY !
- // Workaround for viewing avatars from old viewers that haven't baked hair textures.
- // This is paired with similar code in updateMeshTextures that sets hair mesh color.
- if (i == BAKED_HAIR)
- {
- for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
- {
- mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f );
- }
- }
- }
- }
-
- dirtyMesh();
-}
-
-// static
-void LLVOAvatar::dumpArchetypeXML( void* )
-{
- LLAPRFile outfile;
- outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
- apr_file_t* file = outfile.getFileHandle() ;
- if (!file)
- {
- return;
- }
-
- apr_file_printf( file, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n" );
- apr_file_printf( file, "<linden_genepool version=\"1.0\">\n" );
- apr_file_printf( file, "\n\t<archetype name=\"???\">\n" );
-
- // only body parts, not clothing.
- for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++)
- {
- const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
- apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
-
- for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam())
- {
- LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
- if( (viewer_param->getWearableType() == type) &&
- (viewer_param->isTweakable() ) )
- {
- apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\"/>\n",
- viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight());
- }
- }
-
- for (U8 te = 0; te < TEX_NUM_INDICES; te++)
- {
- if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te) == type)
- {
- // MULTIPLE_WEARABLES: extend to multiple wearables?
- LLViewerTexture* te_image = ((LLVOAvatar *)(gAgentAvatarp))->getImage((ETextureIndex)te, 0);
- if( te_image )
- {
- std::string uuid_str;
- te_image->getID().toString( uuid_str );
- apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
- }
- }
- }
- }
- apr_file_printf( file, "\t</archetype>\n" );
- apr_file_printf( file, "\n</linden_genepool>\n" );
-}
-
-
-void LLVOAvatar::setVisibilityRank(U32 rank)
-{
- if (mDrawable.isNull() || mDrawable->isDead())
- {
- // do nothing
- return;
- }
- mVisibilityRank = rank;
-}
-
-// Assumes LLVOAvatar::sInstances has already been sorted.
-S32 LLVOAvatar::getUnbakedPixelAreaRank()
-{
- S32 rank = 1;
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* inst = (LLVOAvatar*) *iter;
- if (inst == this)
- {
- return rank;
- }
- else if (!inst->isDead() && !inst->isFullyBaked())
- {
- rank++;
- }
- }
-
- llassert(0);
- return 0;
-}
-
-struct CompareScreenAreaGreater
-{
- BOOL operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs)
- {
- return lhs->getPixelArea() > rhs->getPixelArea();
- }
-};
-
-// static
-void LLVOAvatar::cullAvatarsByPixelArea()
-{
- std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater());
-
- // Update the avatars that have changed status
- U32 rank = 2; //1 is reserved for self.
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* inst = (LLVOAvatar*) *iter;
- BOOL culled;
- if (inst->isSelf() || inst->isFullyBaked())
- {
- culled = FALSE;
- }
- else
- {
- culled = TRUE;
- }
-
- if (inst->mCulled != culled)
- {
- inst->mCulled = culled;
- lldebugs << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << llendl;
- inst->updateMeshTextures();
- }
-
- if (inst->isSelf())
- {
- inst->setVisibilityRank(1);
- }
- else if (inst->mDrawable.notNull() && inst->mDrawable->isVisible())
- {
- inst->setVisibilityRank(rank++);
- }
- }
-
- S32 grey_avatars = 0;
- if (LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars))
- {
- LLVOAvatar::deleteCachedImages(false);
- }
- else
- {
- if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame
- {
- sUnbakedUpdateTime = gFrameTimeSeconds;
- sUnbakedTime += gFrameIntervalSeconds;
- }
- if (grey_avatars > 0)
- {
- if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame
- {
- sGreyUpdateTime = gFrameTimeSeconds;
- sGreyTime += gFrameIntervalSeconds;
- }
- }
- }
-}
-
-void LLVOAvatar::startAppearanceAnimation()
-{
- if(!mAppearanceAnimating)
- {
- mAppearanceAnimating = TRUE;
- mAppearanceMorphTimer.reset();
- mLastAppearanceBlendTime = 0.f;
- }
-}
-
-// virtual
-void LLVOAvatar::removeMissingBakedTextures()
-{
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarXmlInfo
-//-----------------------------------------------------------------------------
-
-LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo()
- : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
-{
-}
-
-LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo()
-{
- std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
- std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
- std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
- deleteAndClear(mTexSkinColorInfo);
- deleteAndClear(mTexHairColorInfo);
- deleteAndClear(mTexEyeColorInfo);
- std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
- std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
- std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarBoneInfo::parseXml()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
-{
- if (node->hasName("bone"))
- {
- mIsJoint = TRUE;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!node->getFastAttributeString(name_string, mName))
- {
- llwarns << "Bone without name" << llendl;
- return FALSE;
- }
- }
- else if (node->hasName("collision_volume"))
- {
- mIsJoint = FALSE;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!node->getFastAttributeString(name_string, mName))
- {
- mName = "Collision Volume";
- }
- }
- else
- {
- llwarns << "Invalid node " << node->getName() << llendl;
- return FALSE;
- }
-
- static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
- if (!node->getFastAttributeVector3(pos_string, mPos))
- {
- llwarns << "Bone without position" << llendl;
- return FALSE;
- }
-
- static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
- if (!node->getFastAttributeVector3(rot_string, mRot))
- {
- llwarns << "Bone without rotation" << llendl;
- return FALSE;
- }
-
- static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
- if (!node->getFastAttributeVector3(scale_string, mScale))
- {
- llwarns << "Bone without scale" << llendl;
- return FALSE;
- }
-
- if (mIsJoint)
- {
- static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
- if (!node->getFastAttributeVector3(pivot_string, mPivot))
- {
- llwarns << "Bone without pivot" << llendl;
- return FALSE;
- }
- }
-
- // parse children
- LLXmlTreeNode* child;
- for( child = node->getFirstChild(); child; child = node->getNextChild() )
- {
- LLVOAvatarBoneInfo *child_info = new LLVOAvatarBoneInfo;
- if (!child_info->parseXml(child))
- {
- delete child_info;
- return FALSE;
- }
- mChildList.push_back(child_info);
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo::parseXml()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
-{
- static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
- if (!node->getFastAttributeS32(num_bones_string, mNumBones))
- {
- llwarns << "Couldn't find number of bones." << llendl;
- return FALSE;
- }
-
- static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
- node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
-
- LLXmlTreeNode* child;
- for( child = node->getFirstChild(); child; child = node->getNextChild() )
- {
- LLVOAvatarBoneInfo *info = new LLVOAvatarBoneInfo;
- if (!info->parseXml(child))
- {
- delete info;
- llwarns << "Error parsing bone in skeleton file" << llendl;
- return FALSE;
- }
- mBoneInfoList.push_back(info);
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* node = root->getChildByName( "skeleton" );
- if( !node )
- {
- llwarns << "avatar file: missing <skeleton>" << llendl;
- return FALSE;
- }
-
- LLXmlTreeNode* child;
-
- // SKELETON DISTORTIONS
- for (child = node->getChildByName( "param" );
- child;
- child = node->getNextNamedChild())
- {
- if (!child->getChildByName("param_skeleton"))
- {
- if (child->getChildByName("param_morph"))
- {
- llwarns << "Can't specify morph param in skeleton definition." << llendl;
- }
- else
- {
- llwarns << "Unknown param type." << llendl;
- }
- continue;
- }
-
- LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
- if (!info->parseXml(child))
- {
- delete info;
- return FALSE;
- }
-
- mSkeletalDistortionInfoList.push_back(info);
- }
-
- // ATTACHMENT POINTS
- for (child = node->getChildByName( "attachment_point" );
- child;
- child = node->getNextNamedChild())
- {
- LLVOAvatarAttachmentInfo* info = new LLVOAvatarAttachmentInfo();
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (!child->getFastAttributeString(name_string, info->mName))
- {
- llwarns << "No name supplied for attachment point." << llendl;
- delete info;
- continue;
- }
-
- static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
- if (!child->getFastAttributeString(joint_string, info->mJointName))
- {
- llwarns << "No bone declared in attachment point " << info->mName << llendl;
- delete info;
- continue;
- }
-
- static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
- if (child->getFastAttributeVector3(position_string, info->mPosition))
- {
- info->mHasPosition = TRUE;
- }
-
- static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
- if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
- {
- info->mHasRotation = TRUE;
- }
- static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
- if (child->getFastAttributeS32(group_string, info->mGroup))
- {
- if (info->mGroup == -1)
- info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
- }
-
- static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
- if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
- {
- llwarns << "No id supplied for attachment point " << info->mName << llendl;
- delete info;
- continue;
- }
-
- static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
- child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
-
- static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
- child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
-
- static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
- child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
-
- mAttachmentInfoList.push_back(info);
- }
-
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
- node;
- node = root->getNextNamedChild())
- {
- LLVOAvatarMeshInfo *info = new LLVOAvatarMeshInfo;
-
- // attribute: type
- static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
- if( !node->getFastAttributeString( type_string, info->mType ) )
- {
- llwarns << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << llendl;
- delete info;
- return FALSE; // Ignore this element
- }
-
- static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
- if (!node->getFastAttributeS32( lod_string, info->mLOD ))
- {
- llwarns << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << llendl;
- delete info;
- return FALSE; // Ignore this element
- }
-
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
- {
- llwarns << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << llendl;
- delete info;
- return FALSE; // Ignore this element
- }
-
- static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
- node->getFastAttributeString( reference_string, info->mReferenceMeshName );
-
- // attribute: min_pixel_area
- static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
- static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
- if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
- {
- F32 min_pixel_area = 0.1f;
- if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
- {
- // this is square root of pixel area (sensible to use linear space in defining lods)
- min_pixel_area = min_pixel_area * min_pixel_area;
- }
- info->mMinPixelArea = min_pixel_area;
- }
-
- // Parse visual params for this node only if we haven't already
- for (LLXmlTreeNode* child = node->getChildByName( "param" );
- child;
- child = node->getNextNamedChild())
- {
- if (!child->getChildByName("param_morph"))
- {
- if (child->getChildByName("param_skeleton"))
- {
- llwarns << "Can't specify skeleton param in a mesh definition." << llendl;
- }
- else
- {
- llwarns << "Unknown param type." << llendl;
- }
- continue;
- }
-
- LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
- if (!morphinfo->parseXml(child))
- {
- delete morphinfo;
- delete info;
- return -1;
- }
- BOOL shared = FALSE;
- static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
- child->getFastAttributeBOOL(shared_string, shared);
-
- info->mPolyMorphTargetInfoList.push_back(LLVOAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
- }
-
- mMeshInfoList.push_back(info);
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlColorNodes(): parses <global_color> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
- color_node;
- color_node = root->getNextNamedChild())
- {
- std::string global_color_name;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- if (color_node->getFastAttributeString( name_string, global_color_name ) )
- {
- if( global_color_name == "skin_color" )
- {
- if (mTexSkinColorInfo)
- {
- llwarns << "avatar file: multiple instances of skin_color" << llendl;
- return FALSE;
- }
- mTexSkinColorInfo = new LLTexGlobalColorInfo;
- if( !mTexSkinColorInfo->parseXml( color_node ) )
- {
- deleteAndClear(mTexSkinColorInfo);
- llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl;
- return FALSE;
- }
- }
- else if( global_color_name == "hair_color" )
- {
- if (mTexHairColorInfo)
- {
- llwarns << "avatar file: multiple instances of hair_color" << llendl;
- return FALSE;
- }
- mTexHairColorInfo = new LLTexGlobalColorInfo;
- if( !mTexHairColorInfo->parseXml( color_node ) )
- {
- deleteAndClear(mTexHairColorInfo);
- llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl;
- return FALSE;
- }
- }
- else if( global_color_name == "eye_color" )
- {
- if (mTexEyeColorInfo)
- {
- llwarns << "avatar file: multiple instances of eye_color" << llendl;
- return FALSE;
- }
- mTexEyeColorInfo = new LLTexGlobalColorInfo;
- if( !mTexEyeColorInfo->parseXml( color_node ) )
- {
- llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl;
- return FALSE;
- }
- }
- }
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
-{
- for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
- layer_node;
- layer_node = root->getNextNamedChild())
- {
- LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
- if( layer_info->parseXml( layer_node ) )
- {
- mLayerInfoList.push_back(layer_info);
- }
- else
- {
- delete layer_info;
- llwarns << "avatar file: layer_set->parseXml() failed" << llendl;
- return FALSE;
- }
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
- if( driver )
- {
- for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
- grand_child;
- grand_child = driver->getNextNamedChild())
- {
- if( grand_child->getChildByName( "param_driver" ) )
- {
- LLDriverParamInfo* driver_info = new LLDriverParamInfo();
- if( driver_info->parseXml( grand_child ) )
- {
- mDriverInfoList.push_back(driver_info);
- }
- else
- {
- delete driver_info;
- llwarns << "avatar file: driver_param->parseXml() failed" << llendl;
- return FALSE;
- }
- }
- }
- }
- return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
-{
- LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
- if( !masks )
- {
- return FALSE;
- }
-
- for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
- grand_child;
- grand_child = masks->getNextNamedChild())
- {
- LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo();
-
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
- if (!grand_child->getFastAttributeString(name_string, info->mName))
- {
- llwarns << "No name supplied for morph mask." << llendl;
- delete info;
- continue;
- }
-
- static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
- if (!grand_child->getFastAttributeString(region_string, info->mRegion))
- {
- llwarns << "No region supplied for morph mask." << llendl;
- delete info;
- continue;
- }
-
- static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
- if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
- {
- llwarns << "No layer supplied for morph mask." << llendl;
- delete info;
- continue;
- }
-
- // optional parameter. don't throw a warning if not present.
- static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
- grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
-
- mMorphMaskInfoList.push_back(info);
- }
-
- return TRUE;
-}
-
-//virtual
-void LLVOAvatar::updateRegion(LLViewerRegion *regionp)
-{
- LLViewerObject::updateRegion(regionp);
-}
-
-std::string LLVOAvatar::getFullname() const
-{
- std::string name;
-
- LLNameValue* first = getNVPair("FirstName");
- LLNameValue* last = getNVPair("LastName");
- if (first && last)
- {
- name = LLCacheName::buildFullName( first->getString(), last->getString() );
- }
-
- return name;
-}
-
-LLHost LLVOAvatar::getObjectHost() const
-{
- LLViewerRegion* region = getRegion();
- if (region && !isDead())
- {
- return region->getHost();
- }
- else
- {
- return LLHost::invalid;
- }
-}
-
-//static
-void LLVOAvatar::updateFreezeCounter(S32 counter)
-{
- if(counter)
- {
- sFreezeCounter = counter;
- }
- else if(sFreezeCounter > 0)
- {
- sFreezeCounter--;
- }
- else
- {
- sFreezeCounter = 0;
- }
-}
-
-BOOL LLVOAvatar::updateLOD()
-{
- if (isImpostor())
- {
- return TRUE;
- }
-
- BOOL res = updateJointLODs();
-
- LLFace* facep = mDrawable->getFace(0);
- if (!facep->getVertexBuffer())
- {
- dirtyMesh(2);
- }
-
- if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
- { //LOD changed or new mesh created, allocate new vertex buffer if needed
- updateMeshData();
- mDirtyMesh = 0;
- mNeedsSkin = TRUE;
- mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
- }
- updateVisibility();
-
- return res;
-}
-
-void LLVOAvatar::updateLODRiggedAttachments( void )
-{
- updateLOD();
- rebuildRiggedAttachments();
-}
-U32 LLVOAvatar::getPartitionType() const
-{
- // Avatars merely exist as drawables in the bridge partition
- return LLViewerRegion::PARTITION_BRIDGE;
-}
-
-//static
-void LLVOAvatar::updateImpostors()
-{
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* avatar = (LLVOAvatar*) *iter;
- if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor())
- {
- gPipeline.generateImpostor(avatar);
- }
- }
-}
-
-BOOL LLVOAvatar::isImpostor() const
-{
- return (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD) ? TRUE : FALSE;
-}
-
-
-BOOL LLVOAvatar::needsImpostorUpdate() const
-{
- return mNeedsImpostorUpdate;
-}
-
-const LLVector3& LLVOAvatar::getImpostorOffset() const
-{
- return mImpostorOffset;
-}
-
-const LLVector2& LLVOAvatar::getImpostorDim() const
-{
- return mImpostorDim;
-}
-
-void LLVOAvatar::setImpostorDim(const LLVector2& dim)
-{
- mImpostorDim = dim;
-}
-
-void LLVOAvatar::cacheImpostorValues()
-{
- getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance);
-}
-
-void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const
-{
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- extents[0] = ext[0];
- extents[1] = ext[1];
-
- LLVector3 at = LLViewerCamera::getInstance()->getOrigin()-(getRenderPosition()+mImpostorOffset);
- distance = at.normalize();
- F32 da = 1.f - (at*LLViewerCamera::getInstance()->getAtAxis());
- angle.mV[0] = LLViewerCamera::getInstance()->getYaw()*da;
- angle.mV[1] = LLViewerCamera::getInstance()->getPitch()*da;
- angle.mV[2] = da;
-}
-
-void LLVOAvatar::idleUpdateRenderCost()
-{
- static const U32 ARC_BODY_PART_COST = 20;
- static const U32 ARC_LIMIT = 2048;
-
- static std::set<LLUUID> all_textures;
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
- {
- return;
- }
-
- U32 cost = 0;
- std::set<LLUUID> textures;
-
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- ETextureIndex tex_index = baked_dict->mTextureIndex;
- if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
- {
- if (isTextureVisible(tex_index))
- {
- cost +=ARC_BODY_PART_COST;
- }
- }
- }
-
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isHUDAttachment())
- {
- const LLDrawable* drawable = attached_object->mDrawable;
- if (drawable)
- {
- const LLVOVolume* volume = drawable->getVOVolume();
- if (volume)
- {
- cost += volume->getRenderCost(textures);
- }
- }
- }
- }
-
- }
-
- // Diagnostic output to identify all avatar-related textures.
- // Does not affect rendering cost calculation.
- // Could be wrapped in a debug option if output becomes problematic.
- if (isSelf())
- {
- // print any attachment textures we didn't already know about.
- for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it)
- {
- LLUUID image_id = *it;
- if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
- continue;
- if (all_textures.find(image_id) == all_textures.end())
- {
- // attachment texture not previously seen.
- llinfos << "attachment_texture: " << image_id.asString() << llendl;
- all_textures.insert(image_id);
- }
- }
-
- // print any avatar textures we didn't already know about
- for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
- iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
- ++iter)
- {
- const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
- // TODO: MULTI-WEARABLE: handle multiple textures for self
- const LLViewerTexture* te_image = getImage(iter->first,0);
- if (!te_image)
- continue;
- LLUUID image_id = te_image->getID();
- if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
- continue;
- if (all_textures.find(image_id) == all_textures.end())
- {
- llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
- all_textures.insert(image_id);
- }
- }
- }
-
- cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
-
- setDebugText(llformat("%d", cost));
- F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
- F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f);
- mText->setColor(LLColor4(red,green,0,1));
-}
-
-// static
-BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index)
-{
- if (index < 0 || index >= TEX_NUM_INDICES) return false;
- return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsLocalTexture;
-}
-
-// static
-BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index)
-{
- if (index < 0 || index >= TEX_NUM_INDICES) return false;
- return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsBakedTexture;
-}
-
-const std::string LLVOAvatar::getBakedStatusForPrintout() const
-{
- std::string line;
-
- for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
- iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
- ++iter)
- {
- const ETextureIndex index = iter->first;
- const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
- if (texture_dict->mIsBakedTexture)
- {
- line += texture_dict->mName;
- if (isTextureDefined(index))
- {
- line += "_baked";
- }
- line += " ";
- }
- }
- return line;
-}
-
-
-
-//virtual
-S32 LLVOAvatar::getTexImageSize() const
-{
- return TEX_IMAGE_SIZE_OTHER;
-}
-
-//-----------------------------------------------------------------------------
-// Utility functions
-//-----------------------------------------------------------------------------
-
-F32 calc_bouncy_animation(F32 x)
-{
- return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f;
-}
-
-//virtual
-BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const
-{
- if (isIndexLocalTexture(te))
- {
- return FALSE;
- }
-
- return (getImage(te, index)->getID() != IMG_DEFAULT_AVATAR &&
- getImage(te, index)->getID() != IMG_DEFAULT);
-}
-
-//virtual
-BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const
-{
- if (isIndexLocalTexture(type))
- {
- return isTextureDefined(type, index);
- }
- else
- {
- // baked textures can use TE images directly
- return ((isTextureDefined(type) || isSelf())
- && (getTEImage(type)->getID() != IMG_INVISIBLE
- || LLDrawPoolAlpha::sShowDebugAlpha));
- }
-}
-
-//virtual
-BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const
-{
- // non-self avatars don't have wearables
- return FALSE;
-}
-
+/**
+ * @File llvoavatar.cpp
+ * @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#if LL_MSVC
+// disable warning about boost::lexical_cast returning uninitialized data
+// when it fails to parse the string
+#pragma warning (disable:4701)
+#endif
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvoavatar.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "llaudioengine.h"
+#include "llcachename.h"
+#include "noise.h"
+#include "sound_ids.h"
+
+#include "llagent.h" // Get state values from here
+#include "llagentcamera.h"
+#include "llagentwearables.h"
+#include "llanimationstates.h"
+#include "llavatarnamecache.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llphysicsmotion.h"
+#include "llviewercontrol.h"
+#include "llcallingcard.h" // IDEVO for LLAvatarTracker
+#include "lldrawpoolavatar.h"
+#include "lldriverparam.h"
+#include "lleditingmotion.h"
+#include "llemote.h"
+//#include "llfirstuse.h"
+#include "llheadrotmotion.h"
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h" // for mText/mDebugText
+#include "llkeyframefallmotion.h"
+#include "llkeyframestandmotion.h"
+#include "llkeyframewalkmotion.h"
+#include "llmanipscale.h" // for get_default_max_prim_scale()
+#include "llmeshrepository.h"
+#include "llmutelist.h"
+#include "llmoveview.h"
+#include "llnotificationsutil.h"
+#include "llquantize.h"
+#include "llrand.h"
+#include "llregionhandle.h"
+#include "llresmgr.h"
+#include "llselectmgr.h"
+#include "llsprite.h"
+#include "lltargetingmotion.h"
+#include "lltexlayer.h"
+#include "lltoolmorph.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewermenu.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "llviewershadermgr.h"
+#include "llsky.h"
+#include "llanimstatelabels.h"
+#include "lltrans.h"
+#include "llappearancemgr.h"
+
+#include "llgesturemgr.h" //needed to trigger the voice gesticulations
+#include "llvoiceclient.h"
+#include "llvoicevisualizer.h" // Ventrella
+
+#include "lldebugmessagebox.h"
+extern F32 SPEED_ADJUST_MAX;
+extern F32 SPEED_ADJUST_MAX_SEC;
+extern F32 ANIM_SPEED_MAX;
+extern F32 ANIM_SPEED_MIN;
+
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+#include <boost/lexical_cast.hpp>
+
+// #define OUTPUT_BREAST_DATA
+
+using namespace LLVOAvatarDefines;
+
+//-----------------------------------------------------------------------------
+// Global constants
+//-----------------------------------------------------------------------------
+const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise"
+const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot"
+const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing"
+const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye"
+const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust"
+const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion"
+const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot"
+const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix"
+const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target"
+const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust"
+const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion"
+
+
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+const std::string AVATAR_DEFAULT_CHAR = "avatar";
+
+const S32 MIN_PIXEL_AREA_FOR_COMPOSITE = 1024;
+const F32 SHADOW_OFFSET_AMT = 0.03f;
+
+const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this
+const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations.
+
+const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying
+const F32 PELVIS_LAG_WALKING = 0.4f; // ...while walking
+const F32 PELVIS_LAG_MOUSELOOK = 0.15f;
+const F32 MOUSELOOK_PELVIS_FOLLOW_FACTOR = 0.5f;
+const F32 PELVIS_LAG_WHEN_FOLLOW_CAM_IS_ON = 0.0001f; // not zero! - something gets divided by this!
+
+const F32 PELVIS_ROT_THRESHOLD_SLOW = 60.0f; // amount of deviation allowed between
+const F32 PELVIS_ROT_THRESHOLD_FAST = 2.0f; // the pelvis and the view direction
+ // when moving fast & slow
+const F32 TORSO_NOISE_AMOUNT = 1.0f; // Amount of deviation from up-axis, in degrees
+const F32 TORSO_NOISE_SPEED = 0.2f; // Time scale factor on torso noise.
+
+const F32 BREATHE_ROT_MOTION_STRENGTH = 0.05f;
+const F32 BREATHE_SCALE_MOTION_STRENGTH = 0.005f;
+
+const F32 MIN_SHADOW_HEIGHT = 0.f;
+const F32 MAX_SHADOW_HEIGHT = 0.3f;
+
+const S32 MIN_REQUIRED_PIXEL_AREA_BODY_NOISE = 10000;
+const S32 MIN_REQUIRED_PIXEL_AREA_BREATHE = 10000;
+const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40;
+
+const S32 TEX_IMAGE_SIZE_SELF = 512;
+const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF;
+const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars
+
+const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
+
+const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
+
+// Discard level at which to switch to baked textures
+// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
+const S32 SWITCH_TO_BAKED_DISCARD = 5;
+
+const F32 FOOT_COLLIDE_FUDGE = 0.04f;
+
+const F32 HOVER_EFFECT_MAX_SPEED = 3.f;
+const F32 HOVER_EFFECT_STRENGTH = 0.f;
+const F32 UNDERWATER_EFFECT_STRENGTH = 0.1f;
+const F32 UNDERWATER_FREQUENCY_DAMP = 0.33f;
+const F32 APPEARANCE_MORPH_TIME = 0.65f;
+const F32 TIME_BEFORE_MESH_CLEANUP = 5.f; // seconds
+const S32 AVATAR_RELEASE_THRESHOLD = 10; // number of avatar instances before releasing memory
+const F32 FOOT_GROUND_COLLISION_TOLERANCE = 0.25f;
+const F32 AVATAR_LOD_TWEAK_RANGE = 0.7f;
+const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN;
+const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12;
+const F32 CHAT_FADE_TIME = 8.0;
+const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f;
+
+const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
+
+enum ERenderName
+{
+ RENDER_NAME_NEVER,
+ RENDER_NAME_ALWAYS,
+ RENDER_NAME_FADE
+};
+
+//-----------------------------------------------------------------------------
+// Callback data
+//-----------------------------------------------------------------------------
+
+struct LLTextureMaskData
+{
+ LLTextureMaskData( const LLUUID& id ) :
+ mAvatarID(id),
+ mLastDiscardLevel(S32_MAX)
+ {}
+ LLUUID mAvatarID;
+ S32 mLastDiscardLevel;
+};
+
+/*********************************************************************************
+ ** **
+ ** Begin private LLVOAvatar Support classes
+ **
+ **/
+
+//------------------------------------------------------------------------
+// LLVOBoneInfo
+// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
+//------------------------------------------------------------------------
+class LLVOAvatarBoneInfo
+{
+ friend class LLVOAvatar;
+ friend class LLVOAvatarSkeletonInfo;
+public:
+ LLVOAvatarBoneInfo() : mIsJoint(FALSE) {}
+ ~LLVOAvatarBoneInfo()
+ {
+ std::for_each(mChildList.begin(), mChildList.end(), DeletePointer());
+ }
+ BOOL parseXml(LLXmlTreeNode* node);
+
+private:
+ std::string mName;
+ BOOL mIsJoint;
+ LLVector3 mPos;
+ LLVector3 mRot;
+ LLVector3 mScale;
+ LLVector3 mPivot;
+ typedef std::vector<LLVOAvatarBoneInfo*> child_list_t;
+ child_list_t mChildList;
+};
+
+//------------------------------------------------------------------------
+// LLVOAvatarSkeletonInfo
+// Overall avatar skeleton
+//------------------------------------------------------------------------
+class LLVOAvatarSkeletonInfo
+{
+ friend class LLVOAvatar;
+public:
+ LLVOAvatarSkeletonInfo() :
+ mNumBones(0), mNumCollisionVolumes(0) {}
+ ~LLVOAvatarSkeletonInfo()
+ {
+ std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
+ }
+ BOOL parseXml(LLXmlTreeNode* node);
+ S32 getNumBones() const { return mNumBones; }
+ S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
+
+private:
+ S32 mNumBones;
+ S32 mNumCollisionVolumes;
+ typedef std::vector<LLVOAvatarBoneInfo*> bone_info_list_t;
+ bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// class LLBodyNoiseMotion
+//-----------------------------------------------------------------------------
+class LLBodyNoiseMotion :
+ public LLMotion
+{
+public:
+ // Constructor
+ LLBodyNoiseMotion(const LLUUID &id)
+ : LLMotion(id)
+ {
+ mName = "body_noise";
+ mTorsoState = new LLJointState;
+ }
+
+ // Destructor
+ virtual ~LLBodyNoiseMotion() { }
+
+public:
+ //-------------------------------------------------------------------------
+ // functions to support MotionController and MotionRegistry
+ //-------------------------------------------------------------------------
+ // static constructor
+ // all subclasses must implement such a function and register it
+ static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); }
+
+public:
+ //-------------------------------------------------------------------------
+ // animation callbacks to be implemented by subclasses
+ //-------------------------------------------------------------------------
+
+ // motions must specify whether or not they loop
+ virtual BOOL getLoop() { return TRUE; }
+
+ // motions must report their total duration
+ virtual F32 getDuration() { return 0.0; }
+
+ // motions must report their "ease in" duration
+ virtual F32 getEaseInDuration() { return 0.0; }
+
+ // motions must report their "ease out" duration.
+ virtual F32 getEaseOutDuration() { return 0.0; }
+
+ // motions must report their priority
+ virtual LLJoint::JointPriority getPriority() { return LLJoint::HIGH_PRIORITY; }
+
+ virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; }
+
+ // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
+ virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BODY_NOISE; }
+
+ // run-time (post constructor) initialization,
+ // called after parameters have been set
+ // must return true to indicate success and be available for activation
+ virtual LLMotionInitStatus onInitialize(LLCharacter *character)
+ {
+ if( !mTorsoState->setJoint( character->getJoint("mTorso") ))
+ {
+ return STATUS_FAILURE;
+ }
+
+ mTorsoState->setUsage(LLJointState::ROT);
+
+ addJointState( mTorsoState );
+ return STATUS_SUCCESS;
+ }
+
+ // called when a motion is activated
+ // must return TRUE to indicate success, or else
+ // it will be deactivated
+ virtual BOOL onActivate() { return TRUE; }
+
+ // called per time step
+ // must return TRUE while it is active, and
+ // must return FALSE when the motion is completed.
+ virtual BOOL onUpdate(F32 time, U8* joint_mask)
+ {
+ F32 nx[2];
+ nx[0]=time*TORSO_NOISE_SPEED;
+ nx[1]=0.0f;
+ F32 ny[2];
+ ny[0]=0.0f;
+ ny[1]=time*TORSO_NOISE_SPEED;
+ F32 noiseX = noise2(nx);
+ F32 noiseY = noise2(ny);
+
+ F32 rx = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseX / 0.42f;
+ F32 ry = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseY / 0.42f;
+ LLQuaternion tQn;
+ tQn.setQuat( rx, ry, 0.0f );
+ mTorsoState->setRotation( tQn );
+
+ return TRUE;
+ }
+
+ // called when a motion is deactivated
+ virtual void onDeactivate() {}
+
+private:
+ //-------------------------------------------------------------------------
+ // joint states to be animated
+ //-------------------------------------------------------------------------
+ LLPointer<LLJointState> mTorsoState;
+};
+
+//-----------------------------------------------------------------------------
+// class LLBreatheMotionRot
+//-----------------------------------------------------------------------------
+class LLBreatheMotionRot :
+ public LLMotion
+{
+public:
+ // Constructor
+ LLBreatheMotionRot(const LLUUID &id) :
+ LLMotion(id),
+ mBreatheRate(1.f),
+ mCharacter(NULL)
+ {
+ mName = "breathe_rot";
+ mChestState = new LLJointState;
+ }
+
+ // Destructor
+ virtual ~LLBreatheMotionRot() {}
+
+public:
+ //-------------------------------------------------------------------------
+ // functions to support MotionController and MotionRegistry
+ //-------------------------------------------------------------------------
+ // static constructor
+ // all subclasses must implement such a function and register it
+ static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); }
+
+public:
+ //-------------------------------------------------------------------------
+ // animation callbacks to be implemented by subclasses
+ //-------------------------------------------------------------------------
+
+ // motions must specify whether or not they loop
+ virtual BOOL getLoop() { return TRUE; }
+
+ // motions must report their total duration
+ virtual F32 getDuration() { return 0.0; }
+
+ // motions must report their "ease in" duration
+ virtual F32 getEaseInDuration() { return 0.0; }
+
+ // motions must report their "ease out" duration.
+ virtual F32 getEaseOutDuration() { return 0.0; }
+
+ // motions must report their priority
+ virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; }
+
+ virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
+
+ // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
+ virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_BREATHE; }
+
+ // run-time (post constructor) initialization,
+ // called after parameters have been set
+ // must return true to indicate success and be available for activation
+ virtual LLMotionInitStatus onInitialize(LLCharacter *character)
+ {
+ mCharacter = character;
+ BOOL success = true;
+
+ if ( !mChestState->setJoint( character->getJoint( "mChest" ) ) ) { success = false; }
+
+ if ( success )
+ {
+ mChestState->setUsage(LLJointState::ROT);
+ addJointState( mChestState );
+ }
+
+ if ( success )
+ {
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ return STATUS_FAILURE;
+ }
+ }
+
+ // called when a motion is activated
+ // must return TRUE to indicate success, or else
+ // it will be deactivated
+ virtual BOOL onActivate() { return TRUE; }
+
+ // called per time step
+ // must return TRUE while it is active, and
+ // must return FALSE when the motion is completed.
+ virtual BOOL onUpdate(F32 time, U8* joint_mask)
+ {
+ mBreatheRate = 1.f;
+
+ F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH);
+
+ mChestState->setRotation(LLQuaternion(breathe_amt, LLVector3(0.f, 1.f, 0.f)));
+
+ return TRUE;
+ }
+
+ // called when a motion is deactivated
+ virtual void onDeactivate() {}
+
+private:
+ //-------------------------------------------------------------------------
+ // joint states to be animated
+ //-------------------------------------------------------------------------
+ LLPointer<LLJointState> mChestState;
+ F32 mBreatheRate;
+ LLCharacter* mCharacter;
+};
+
+//-----------------------------------------------------------------------------
+// class LLPelvisFixMotion
+//-----------------------------------------------------------------------------
+class LLPelvisFixMotion :
+ public LLMotion
+{
+public:
+ // Constructor
+ LLPelvisFixMotion(const LLUUID &id)
+ : LLMotion(id), mCharacter(NULL)
+ {
+ mName = "pelvis_fix";
+
+ mPelvisState = new LLJointState;
+ }
+
+ // Destructor
+ virtual ~LLPelvisFixMotion() { }
+
+public:
+ //-------------------------------------------------------------------------
+ // functions to support MotionController and MotionRegistry
+ //-------------------------------------------------------------------------
+ // static constructor
+ // all subclasses must implement such a function and register it
+ static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); }
+
+public:
+ //-------------------------------------------------------------------------
+ // animation callbacks to be implemented by subclasses
+ //-------------------------------------------------------------------------
+
+ // motions must specify whether or not they loop
+ virtual BOOL getLoop() { return TRUE; }
+
+ // motions must report their total duration
+ virtual F32 getDuration() { return 0.0; }
+
+ // motions must report their "ease in" duration
+ virtual F32 getEaseInDuration() { return 0.5f; }
+
+ // motions must report their "ease out" duration.
+ virtual F32 getEaseOutDuration() { return 0.5f; }
+
+ // motions must report their priority
+ virtual LLJoint::JointPriority getPriority() { return LLJoint::LOW_PRIORITY; }
+
+ virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
+
+ // called to determine when a motion should be activated/deactivated based on avatar pixel coverage
+ virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX; }
+
+ // run-time (post constructor) initialization,
+ // called after parameters have been set
+ // must return true to indicate success and be available for activation
+ virtual LLMotionInitStatus onInitialize(LLCharacter *character)
+ {
+ mCharacter = character;
+
+ if (!mPelvisState->setJoint( character->getJoint("mPelvis")))
+ {
+ return STATUS_FAILURE;
+ }
+
+ mPelvisState->setUsage(LLJointState::POS);
+
+ addJointState( mPelvisState );
+ return STATUS_SUCCESS;
+ }
+
+ // called when a motion is activated
+ // must return TRUE to indicate success, or else
+ // it will be deactivated
+ virtual BOOL onActivate() { return TRUE; }
+
+ // called per time step
+ // must return TRUE while it is active, and
+ // must return FALSE when the motion is completed.
+ virtual BOOL onUpdate(F32 time, U8* joint_mask)
+ {
+ mPelvisState->setPosition(LLVector3::zero);
+
+ return TRUE;
+ }
+
+ // called when a motion is deactivated
+ virtual void onDeactivate() {}
+
+private:
+ //-------------------------------------------------------------------------
+ // joint states to be animated
+ //-------------------------------------------------------------------------
+ LLPointer<LLJointState> mPelvisState;
+ LLCharacter* mCharacter;
+};
+
+/**
+ **
+ ** End LLVOAvatar Support classes
+ ** **
+ *********************************************************************************/
+
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+LLXmlTree LLVOAvatar::sXMLTree;
+LLXmlTree LLVOAvatar::sSkeletonXMLTree;
+LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL;
+LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL;
+LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL;
+S32 LLVOAvatar::sFreezeCounter = 0;
+U32 LLVOAvatar::sMaxVisible = 12;
+F32 LLVOAvatar::sRenderDistance = 256.f;
+S32 LLVOAvatar::sNumVisibleAvatars = 0;
+S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
+
+const LLUUID LLVOAvatar::sStepSoundOnLand("e8af4a28-aa83-4310-a7c4-c047e15ea0df");
+const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] =
+{
+ SND_STONE_RUBBER,
+ SND_METAL_RUBBER,
+ SND_GLASS_RUBBER,
+ SND_WOOD_RUBBER,
+ SND_FLESH_RUBBER,
+ SND_RUBBER_PLASTIC,
+ SND_RUBBER_RUBBER
+};
+
+S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS;
+BOOL LLVOAvatar::sRenderGroupTitles = TRUE;
+S32 LLVOAvatar::sNumVisibleChatBubbles = 0;
+BOOL LLVOAvatar::sDebugInvisible = FALSE;
+BOOL LLVOAvatar::sShowAttachmentPoints = FALSE;
+BOOL LLVOAvatar::sShowAnimationDebug = FALSE;
+BOOL LLVOAvatar::sShowFootPlane = FALSE;
+BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
+F32 LLVOAvatar::sLODFactor = 1.f;
+F32 LLVOAvatar::sPhysicsLODFactor = 1.f;
+BOOL LLVOAvatar::sUseImpostors = FALSE;
+BOOL LLVOAvatar::sJointDebug = FALSE;
+
+F32 LLVOAvatar::sUnbakedTime = 0.f;
+F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
+F32 LLVOAvatar::sGreyTime = 0.f;
+F32 LLVOAvatar::sGreyUpdateTime = 0.f;
+
+//-----------------------------------------------------------------------------
+// Helper functions
+//-----------------------------------------------------------------------------
+static F32 calc_bouncy_animation(F32 x);
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar()
+//-----------------------------------------------------------------------------
+LLVOAvatar::LLVOAvatar(const LLUUID& id,
+ const LLPCode pcode,
+ LLViewerRegion* regionp) :
+ LLViewerObject(id, pcode, regionp),
+ mIsDummy(FALSE),
+ mSpecialRenderMode(0),
+ mTurning(FALSE),
+ mPelvisToFoot(0.f),
+ mLastSkeletonSerialNum( 0 ),
+ mHeadOffset(),
+ mIsSitting(FALSE),
+ mTimeVisible(),
+ mTyping(FALSE),
+ mMeshValid(FALSE),
+ mVisible(FALSE),
+ mWindFreq(0.f),
+ mRipplePhase( 0.f ),
+ mBelowWater(FALSE),
+ mLastAppearanceBlendTime(0.f),
+ mAppearanceAnimating(FALSE),
+ mNameString(),
+ mTitle(),
+ mNameAway(false),
+ mNameBusy(false),
+ mNameMute(false),
+ mNameAppearance(false),
+ mNameFriend(false),
+ mNameAlpha(0.f),
+ mRenderGroupTitles(sRenderGroupTitles),
+ mNameCloud(false),
+ mFirstTEMessageReceived( FALSE ),
+ mFirstAppearanceMessageReceived( FALSE ),
+ mCulled( FALSE ),
+ mVisibilityRank(0),
+ mTexSkinColor( NULL ),
+ mTexHairColor( NULL ),
+ mTexEyeColor( NULL ),
+ mNeedsSkin(FALSE),
+ mLastSkinTime(0.f),
+ mUpdatePeriod(1),
+ mFullyLoaded(FALSE),
+ mPreviousFullyLoaded(FALSE),
+ mFullyLoadedInitialized(FALSE),
+ mSupportsAlphaLayers(FALSE),
+ mLoadedCallbacksPaused(FALSE),
+ mHasPelvisOffset( FALSE )
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+ //VTResume(); // VTune
+
+ // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline
+ const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
+ mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
+
+ lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl;
+
+ mPelvisp = NULL;
+
+ mBakedTextureDatas.resize(BAKED_NUM_INDICES);
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
+ {
+ mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR;
+ mBakedTextureDatas[i].mTexLayerSet = NULL;
+ mBakedTextureDatas[i].mIsLoaded = false;
+ mBakedTextureDatas[i].mIsUsed = false;
+ mBakedTextureDatas[i].mMaskTexName = 0;
+ mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i);
+ }
+
+ mDirtyMesh = 2; // Dirty geometry, need to regenerate.
+ mMeshTexturesDirty = FALSE;
+ mHeadp = NULL;
+
+ mIsBuilt = FALSE;
+
+ mNumJoints = 0;
+ mSkeleton = NULL;
+
+ mNumCollisionVolumes = 0;
+ mCollisionVolumes = NULL;
+
+ // set up animation variables
+ mSpeed = 0.f;
+ setAnimationData("Speed", &mSpeed);
+
+ mNeedsImpostorUpdate = TRUE;
+ mNeedsAnimUpdate = TRUE;
+
+ mImpostorDistance = 0;
+ mImpostorPixelArea = 0;
+
+ setNumTEs(TEX_NUM_INDICES);
+
+ mbCanSelect = TRUE;
+
+ mSignaledAnimations.clear();
+ mPlayingAnimations.clear();
+
+ mWasOnGroundLeft = FALSE;
+ mWasOnGroundRight = FALSE;
+
+ mTimeLast = 0.0f;
+ mSpeedAccum = 0.0f;
+
+ mRippleTimeLast = 0.f;
+
+ mInAir = FALSE;
+
+ mStepOnLand = TRUE;
+ mStepMaterial = 0;
+
+ mLipSyncActive = false;
+ mOohMorph = NULL;
+ mAahMorph = NULL;
+
+ mCurrentGesticulationLevel = 0;
+
+ mRuthTimer.reset();
+ mRuthDebugTimer.reset();
+ mDebugExistenceTimer.reset();
+ mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
+ mLastPelvisToFoot = 0.0f;
+ mPelvisFixup = 0.0f;
+ mLastPelvisFixup = 0.0f;
+}
+
+//------------------------------------------------------------------------
+// LLVOAvatar::~LLVOAvatar()
+//------------------------------------------------------------------------
+LLVOAvatar::~LLVOAvatar()
+{
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (!mFullyLoaded)
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args);
+ }
+ else
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftNotification",args);
+ }
+
+ }
+ lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
+
+ mRoot.removeAllChildren();
+
+ deleteAndClearArray(mSkeleton);
+ deleteAndClearArray(mCollisionVolumes);
+
+ mNumJoints = 0;
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ deleteAndClear(mBakedTextureDatas[i].mTexLayerSet);
+ mBakedTextureDatas[i].mMeshes.clear();
+
+ for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin();
+ iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++)
+ {
+ LLMaskedMorph* masked_morph = (*iter2);
+ delete masked_morph;
+ }
+ }
+
+ std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
+ mAttachmentPoints.clear();
+
+ deleteAndClear(mTexSkinColor);
+ deleteAndClear(mTexHairColor);
+ deleteAndClear(mTexEyeColor);
+
+ std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer());
+ mMeshes.clear();
+
+ for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
+ jointIter != mMeshLOD.end();
+ ++jointIter)
+ {
+ LLViewerJoint* joint = (LLViewerJoint *) *jointIter;
+ std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
+ joint->mMeshParts.clear();
+ }
+ std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
+ mMeshLOD.clear();
+
+ mDead = TRUE;
+
+ mAnimationSources.clear();
+ LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
+
+ lldebugs << "LLVOAvatar Destructor end" << llendl;
+}
+
+void LLVOAvatar::markDead()
+{
+ if (mNameText)
+ {
+ mNameText->markDead();
+ mNameText = NULL;
+ sNumVisibleChatBubbles--;
+ }
+ mVoiceVisualizer->markDead();
+ LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
+ LLViewerObject::markDead();
+}
+
+
+BOOL LLVOAvatar::isFullyBaked()
+{
+ if (mIsDummy) return TRUE;
+ if (getNumTEs() == 0) return FALSE;
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex)
+ && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void LLVOAvatar::deleteLayerSetCaches(bool clearAll)
+{
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ if (mBakedTextureDatas[i].mTexLayerSet)
+ {
+ // ! BACKWARDS COMPATIBILITY !
+ // Can be removed after hair baking is mandatory on the grid
+ if ((i != BAKED_HAIR || isSelf()) && !clearAll)
+ {
+ mBakedTextureDatas[i].mTexLayerSet->deleteCaches();
+ }
+ }
+ if (mBakedTextureDatas[i].mMaskTexName)
+ {
+ glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName));
+ mBakedTextureDatas[i].mMaskTexName = 0 ;
+ }
+ }
+}
+
+// static
+BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars)
+{
+ BOOL res = TRUE;
+ grey_avatars = 0;
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* inst = (LLVOAvatar*) *iter;
+ if( inst->isDead() )
+ {
+ continue;
+ }
+ else if( !inst->isFullyBaked() )
+ {
+ res = FALSE;
+ if (inst->mHasGrey)
+ {
+ ++grey_avatars;
+ }
+ }
+ }
+ return res;
+}
+
+// static
+void LLVOAvatar::dumpBakedStatus()
+{
+ LLVector3d camera_pos_global = gAgentCamera.getCameraPositionGlobal();
+
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* inst = (LLVOAvatar*) *iter;
+ llinfos << "Avatar ";
+
+ LLNameValue* firstname = inst->getNVPair("FirstName");
+ LLNameValue* lastname = inst->getNVPair("LastName");
+
+ if( firstname )
+ {
+ llcont << firstname->getString();
+ }
+ if( lastname )
+ {
+ llcont << " " << lastname->getString();
+ }
+
+ llcont << " " << inst->mID;
+
+ if( inst->isDead() )
+ {
+ llcont << " DEAD ("<< inst->getNumRefs() << " refs)";
+ }
+
+ if( inst->isSelf() )
+ {
+ llcont << " (self)";
+ }
+
+
+ F64 dist_to_camera = (inst->getPositionGlobal() - camera_pos_global).length();
+ llcont << " " << dist_to_camera << "m ";
+
+ llcont << " " << inst->mPixelArea << " pixels";
+
+ if( inst->isVisible() )
+ {
+ llcont << " (visible)";
+ }
+ else
+ {
+ llcont << " (not visible)";
+ }
+
+ if( inst->isFullyBaked() )
+ {
+ llcont << " Baked";
+ }
+ else
+ {
+ llcont << " Unbaked (";
+
+ for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
+ ++iter)
+ {
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second;
+ const ETextureIndex index = baked_dict->mTextureIndex;
+ if (!inst->isTextureDefined(index))
+ {
+ llcont << " " << LLVOAvatarDictionary::getInstance()->getTexture(index)->mName;
+ }
+ }
+ llcont << " ) " << inst->getUnbakedPixelAreaRank();
+ if( inst->isCulled() )
+ {
+ llcont << " culled";
+ }
+ }
+ llcont << llendl;
+ }
+}
+
+//static
+void LLVOAvatar::restoreGL()
+{
+ if (!isAgentAvatarValid()) return;
+
+ gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
+ for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)
+ {
+ gAgentAvatarp->invalidateComposite(gAgentAvatarp->mBakedTextureDatas[i].mTexLayerSet, FALSE);
+ }
+ gAgentAvatarp->updateMeshTextures();
+}
+
+//static
+void LLVOAvatar::destroyGL()
+{
+ deleteCachedImages();
+
+ resetImpostors();
+}
+
+//static
+void LLVOAvatar::resetImpostors()
+{
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*) *iter;
+ avatar->mImpostor.release();
+ }
+}
+
+// static
+void LLVOAvatar::deleteCachedImages(bool clearAll)
+{
+ if (LLTexLayerSet::sHasCaches)
+ {
+ lldebugs << "Deleting layer set caches" << llendl;
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* inst = (LLVOAvatar*) *iter;
+ inst->deleteLayerSetCaches(clearAll);
+ }
+ LLTexLayerSet::sHasCaches = FALSE;
+ }
+ LLVOAvatarSelf::deleteScratchTextures();
+ LLTexLayerStaticImageList::getInstance()->deleteCachedImages();
+}
+
+
+//------------------------------------------------------------------------
+// static
+// LLVOAvatar::initClass()
+//------------------------------------------------------------------------
+void LLVOAvatar::initClass()
+{
+ std::string xmlFile;
+
+ xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
+ BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
+ if (!success)
+ {
+ llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = sXMLTree.getRoot();
+ if (!root)
+ {
+ llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // <linden_avatar version="1.0"> (root)
+ //-------------------------------------------------------------------------
+ if( !root->hasName( "linden_avatar" ) )
+ {
+ llerrs << "Invalid avatar file header: " << xmlFile << llendl;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ {
+ llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl;
+ }
+
+ S32 wearable_def_version = 1;
+ static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
+ root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
+ LLWearable::setCurrentDefinitionVersion( wearable_def_version );
+
+ std::string mesh_file_name;
+
+ LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
+ if (!skeleton_node)
+ {
+ llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl;
+ return;
+ }
+
+ std::string skeleton_file_name;
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+ {
+ llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl;
+ }
+
+ std::string skeleton_path;
+ skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
+ if (!parseSkeletonFile(skeleton_path))
+ {
+ llerrs << "Error parsing skeleton file: " << skeleton_path << llendl;
+ }
+
+ // Process XML data
+
+ // avatar_skeleton.xml
+ llassert(!sAvatarSkeletonInfo);
+ sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo;
+ if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot()))
+ {
+ llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl;
+ }
+ // parse avatar_lad.xml
+ llassert(!sAvatarXmlInfo);
+ sAvatarXmlInfo = new LLVOAvatarXmlInfo;
+ if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+ if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+ if (!sAvatarXmlInfo->parseXmlColorNodes(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+ if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+ if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+ if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
+ {
+ llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+ }
+
+ gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION,"physics_motion");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target");
+ gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust");
+}
+
+
+void LLVOAvatar::cleanupClass()
+{
+ deleteAndClear(sAvatarXmlInfo);
+ sSkeletonXMLTree.cleanup();
+ sXMLTree.cleanup();
+}
+
+void LLVOAvatar::initInstance(void)
+{
+ //-------------------------------------------------------------------------
+ // initialize joint, mesh and shape members
+ //-------------------------------------------------------------------------
+ mRoot.setName( "mRoot" );
+
+ for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
+ ++iter)
+ {
+ const EMeshIndex mesh_index = iter->first;
+ const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second;
+ LLViewerJoint* joint = new LLViewerJoint();
+ joint->setName(mesh_dict->mName);
+ joint->setMeshID(mesh_index);
+ mMeshLOD.push_back(joint);
+
+ /* mHairLOD.setName("mHairLOD");
+ mHairMesh0.setName("mHairMesh0");
+ mHairMesh0.setMeshID(MESH_ID_HAIR);
+ mHairMesh1.setName("mHairMesh1"); */
+ for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
+ {
+ LLViewerJointMesh* mesh = new LLViewerJointMesh();
+ std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast<std::string>(lod);
+ // We pre-pended an m - need to capitalize first character for camelCase
+ mesh_name[1] = toupper(mesh_name[1]);
+ mesh->setName(mesh_name);
+ mesh->setMeshID(mesh_index);
+ mesh->setPickName(mesh_dict->mPickName);
+ mesh->setIsTransparent(FALSE);
+ switch((int)mesh_index)
+ {
+ case MESH_ID_HAIR:
+ mesh->setIsTransparent(TRUE);
+ break;
+ case MESH_ID_SKIRT:
+ mesh->setIsTransparent(TRUE);
+ break;
+ case MESH_ID_EYEBALL_LEFT:
+ case MESH_ID_EYEBALL_RIGHT:
+ mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f );
+ break;
+ }
+
+ joint->mMeshParts.push_back(mesh);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // associate baked textures with meshes
+ //-------------------------------------------------------------------------
+ for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
+ ++iter)
+ {
+ const EMeshIndex mesh_index = iter->first;
+ const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second;
+ const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID;
+ // Skip it if there's no associated baked texture.
+ if (baked_texture_index == BAKED_NUM_INDICES) continue;
+
+ for (std::vector<LLViewerJointMesh* >::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin();
+ iter != mMeshLOD[mesh_index]->mMeshParts.end();
+ ++iter)
+ {
+ LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter;
+ mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh);
+ }
+ }
+
+
+ //-------------------------------------------------------------------------
+ // register motions
+ //-------------------------------------------------------------------------
+ if (LLCharacter::sInstances.size() == 1)
+ {
+ LLKeyframeMotion::setVFS(gStaticVFS);
+ registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create );
+ registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create );
+ registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create );
+ registerMotion( ANIM_AGENT_FEMALE_RUN_NEW, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_FEMALE_WALK_NEW, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_RUN_NEW, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create );
+ registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create );
+ registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create );
+
+ // motions without a start/stop bit
+ registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create );
+ registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create );
+ registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create );
+ registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create );
+ registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create );
+ registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create );
+ registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create );
+ registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create );
+ registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create );
+ registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create );
+ registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create );
+ registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create );
+ registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create );
+
+ }
+
+ buildCharacter();
+
+ // preload specific motions here
+ createMotion( ANIM_AGENT_CUSTOMIZE);
+ createMotion( ANIM_AGENT_CUSTOMIZE_DONE);
+
+ //VTPause(); // VTune
+
+ mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
+
+}
+
+const LLVector3 LLVOAvatar::getRenderPosition() const
+{
+ if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
+ {
+ return getPositionAgent();
+ }
+ else if (isRoot())
+ {
+ if ( !mHasPelvisOffset )
+ {
+ return mDrawable->getPositionAgent();
+ }
+ else
+ {
+ //Apply a pelvis fixup (as defined by the avs skin)
+ LLVector3 pos = mDrawable->getPositionAgent();
+ pos[VZ] += mPelvisFixup;
+ return pos;
+ }
+ }
+ else
+ {
+ return getPosition() * mDrawable->getParent()->getRenderMatrix();
+ }
+}
+
+void LLVOAvatar::updateDrawable(BOOL force_damped)
+{
+ clearChanged(SHIFTED);
+}
+
+void LLVOAvatar::onShift(const LLVector4a& shift_vector)
+{
+ const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector);
+ mLastAnimExtents[0] += shift;
+ mLastAnimExtents[1] += shift;
+ mNeedsImpostorUpdate = TRUE;
+ mNeedsAnimUpdate = TRUE;
+}
+
+void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
+{
+ if (isImpostor() && !needsImpostorUpdate())
+ {
+ LLVector3 delta = getRenderPosition() -
+ ((LLVector3(mDrawable->getPositionGroup().getF32ptr())-mImpostorOffset));
+
+ newMin.load3( (mLastAnimExtents[0] + delta).mV);
+ newMax.load3( (mLastAnimExtents[1] + delta).mV);
+ }
+ else
+ {
+ getSpatialExtents(newMin,newMax);
+ mLastAnimExtents[0].set(newMin.getF32ptr());
+ mLastAnimExtents[1].set(newMax.getF32ptr());
+ LLVector4a pos_group;
+ pos_group.setAdd(newMin,newMax);
+ pos_group.mul(0.5f);
+ mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();
+ mDrawable->setPositionGroup(pos_group);
+ }
+}
+
+void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
+{
+ LLVector4a buffer(0.25f);
+ LLVector4a pos;
+ pos.load3(getRenderPosition().mV);
+ newMin.setSub(pos, buffer);
+ newMax.setAdd(pos, buffer);
+
+ float max_attachment_span = get_default_max_prim_scale() * 5.0f;
+
+ //stretch bounding box by joint positions
+ for (polymesh_map_t::iterator i = mMeshes.begin(); i != mMeshes.end(); ++i)
+ {
+ LLPolyMesh* mesh = i->second;
+ for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
+ {
+ LLVector4a trans;
+ trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV);
+ update_min_max(newMin, newMax, trans);
+ }
+ }
+
+ LLVector4a center, size;
+ center.setAdd(newMin, newMax);
+ center.mul(0.5f);
+
+ size.setSub(newMax,newMin);
+ size.mul(0.5f);
+
+ mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
+
+ //stretch bounding box by attachments
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+
+ if (!attachment->getValid())
+ {
+ continue ;
+ }
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object && !attached_object->isHUDAttachment())
+ {
+ LLDrawable* drawable = attached_object->mDrawable;
+ if (drawable && !drawable->isState(LLDrawable::RIGGED))
+ {
+ LLSpatialBridge* bridge = drawable->getSpatialBridge();
+ if (bridge)
+ {
+ const LLVector4a* ext = bridge->getSpatialExtents();
+ LLVector4a distance;
+ distance.setSub(ext[1], ext[0]);
+ LLVector4a max_span(max_attachment_span);
+
+ S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7;
+
+ // Only add the prim to spatial extents calculations if it isn't a megaprim.
+ // max_attachment_span calculated at the start of the function
+ // (currently 5 times our max prim size)
+ if (lt == 0x7)
+ {
+ update_min_max(newMin,newMax,ext[0]);
+ update_min_max(newMin,newMax,ext[1]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //pad bounding box
+
+ newMin.sub(buffer);
+ newMax.add(buffer);
+}
+
+//-----------------------------------------------------------------------------
+// renderCollisionVolumes()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::renderCollisionVolumes()
+{
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ mCollisionVolumes[i].renderCollision();
+ }
+
+ if (mNameText.notNull())
+ {
+ LLVector3 unused;
+ mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE);
+ }
+}
+
+BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+ S32 face,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection,
+ LLVector2* tex_coord,
+ LLVector3* normal,
+ LLVector3* bi_normal)
+{
+ if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar)
+ {
+ return FALSE;
+ }
+
+ if (lineSegmentBoundingBox(start, end))
+ {
+ for (S32 i = 0; i < mNumCollisionVolumes; ++i)
+ {
+ mCollisionVolumes[i].updateWorldMatrix();
+
+ glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix);
+ glh::matrix4f inverse = mat.inverse();
+ glh::matrix4f norm_mat = inverse.transpose();
+
+ glh::vec3f p1(start.mV);
+ glh::vec3f p2(end.mV);
+
+ inverse.mult_matrix_vec(p1);
+ inverse.mult_matrix_vec(p2);
+
+ LLVector3 position;
+ LLVector3 norm;
+
+ if (linesegment_sphere(LLVector3(p1.v), LLVector3(p2.v), LLVector3(0,0,0), 1.f, position, norm))
+ {
+ glh::vec3f res_pos(position.mV);
+ mat.mult_matrix_vec(res_pos);
+
+ norm.normalize();
+ glh::vec3f res_norm(norm.mV);
+ norm_mat.mult_matrix_dir(res_norm);
+
+ if (intersection)
+ {
+ *intersection = LLVector3(res_pos.v);
+ }
+
+ if (normal)
+ {
+ *normal = LLVector3(res_norm.v);
+ }
+
+ return TRUE;
+ }
+ }
+ }
+
+ LLVector3 position;
+ if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position))
+ {
+ if (intersection)
+ {
+ *intersection = position;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// parseSkeletonFile()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ //-------------------------------------------------------------------------
+ // parse the file
+ //-------------------------------------------------------------------------
+ BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE );
+
+ if (!parsesuccess)
+ {
+ llerrs << "Can't parse skeleton file: " << filename << llendl;
+ return FALSE;
+ }
+
+ // now sanity check xml file
+ LLXmlTreeNode* root = sSkeletonXMLTree.getRoot();
+ if (!root)
+ {
+ llerrs << "No root node found in avatar skeleton file: " << filename << llendl;
+ return FALSE;
+ }
+
+ if( !root->hasName( "linden_skeleton" ) )
+ {
+ llerrs << "Invalid avatar skeleton file header: " << filename << llendl;
+ return FALSE;
+ }
+
+ std::string version;
+ static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+ if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ {
+ llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// setupBone()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &volume_num, S32 &joint_num)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ LLViewerJoint* joint = NULL;
+
+ if (info->mIsJoint)
+ {
+ joint = (LLViewerJoint*)getCharacterJoint(joint_num);
+ if (!joint)
+ {
+ llwarns << "Too many bones" << llendl;
+ return FALSE;
+ }
+ joint->setName( info->mName );
+ }
+ else // collision volume
+ {
+ if (volume_num >= (S32)mNumCollisionVolumes)
+ {
+ llwarns << "Too many bones" << llendl;
+ return FALSE;
+ }
+ joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]);
+ joint->setName( info->mName );
+ }
+
+ // add to parent
+ if (parent)
+ {
+ parent->addChild( joint );
+ }
+
+ joint->setPosition(info->mPos);
+ joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
+ info->mRot.mV[VZ], LLQuaternion::XYZ));
+ joint->setScale(info->mScale);
+
+ joint->setDefaultFromCurrentXform();
+
+ if (info->mIsJoint)
+ {
+ joint->setSkinOffset( info->mPivot );
+ joint_num++;
+ }
+ else // collision volume
+ {
+ volume_num++;
+ }
+
+ // setup children
+ LLVOAvatarBoneInfo::child_list_t::const_iterator iter;
+ for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
+ {
+ LLVOAvatarBoneInfo *child_info = *iter;
+ if (!setupBone(child_info, joint, volume_num, joint_num))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// buildSkeleton()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ //-------------------------------------------------------------------------
+ // allocate joints
+ //-------------------------------------------------------------------------
+ if (!allocateCharacterJoints(info->mNumBones))
+ {
+ llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl;
+ return FALSE;
+ }
+
+ //-------------------------------------------------------------------------
+ // allocate volumes
+ //-------------------------------------------------------------------------
+ if (info->mNumCollisionVolumes)
+ {
+ if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
+ {
+ llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl;
+ return FALSE;
+ }
+ }
+
+ S32 current_joint_num = 0;
+ S32 current_volume_num = 0;
+ LLVOAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
+ for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
+ {
+ LLVOAvatarBoneInfo *info = *iter;
+ if (!setupBone(info, NULL, current_volume_num, current_joint_num))
+ {
+ llerrs << "Error parsing bone in skeleton file" << llendl;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+LLVOAvatar* LLVOAvatar::asAvatar()
+{
+ return this;
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::startDefaultMotions()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::startDefaultMotions()
+{
+ //-------------------------------------------------------------------------
+ // start default motions
+ //-------------------------------------------------------------------------
+ startMotion( ANIM_AGENT_HEAD_ROT );
+ startMotion( ANIM_AGENT_EYE );
+ startMotion( ANIM_AGENT_BODY_NOISE );
+ startMotion( ANIM_AGENT_BREATHE_ROT );
+ startMotion( ANIM_AGENT_PHYSICS_MOTION );
+ startMotion( ANIM_AGENT_HAND_MOTION );
+ startMotion( ANIM_AGENT_PELVIS_FIX );
+
+ //-------------------------------------------------------------------------
+ // restart any currently active motions
+ //-------------------------------------------------------------------------
+ processAnimationStateChanges();
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::buildCharacter()
+// Deferred initialization and rebuild of the avatar.
+//-----------------------------------------------------------------------------
+void LLVOAvatar::buildCharacter()
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ //-------------------------------------------------------------------------
+ // remove all references to our existing skeleton
+ // so we can rebuild it
+ //-------------------------------------------------------------------------
+ flushAllMotions();
+
+ //-------------------------------------------------------------------------
+ // remove all of mRoot's children
+ //-------------------------------------------------------------------------
+ mRoot.removeAllChildren();
+ mIsBuilt = FALSE;
+
+ //-------------------------------------------------------------------------
+ // clear mesh data
+ //-------------------------------------------------------------------------
+ for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
+ jointIter != mMeshLOD.end(); ++jointIter)
+ {
+ LLViewerJoint* joint = (LLViewerJoint*) *jointIter;
+ for (std::vector<LLViewerJointMesh*>::iterator meshIter = joint->mMeshParts.begin();
+ meshIter != joint->mMeshParts.end(); ++meshIter)
+ {
+ LLViewerJointMesh * mesh = (LLViewerJointMesh *) *meshIter;
+ mesh->setMesh(NULL);
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // (re)load our skeleton and meshes
+ //-------------------------------------------------------------------------
+ LLTimer timer;
+
+ BOOL status = loadAvatar();
+ stop_glerror();
+
+// gPrintMessagesThisFrame = TRUE;
+ lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl;
+
+ if (!status)
+ {
+ if (isSelf())
+ {
+ llerrs << "Unable to load user's avatar" << llendl;
+ }
+ else
+ {
+ llwarns << "Unable to load other's avatar" << llendl;
+ }
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize "well known" joint pointers
+ //-------------------------------------------------------------------------
+ mPelvisp = (LLViewerJoint*)mRoot.findJoint("mPelvis");
+ mTorsop = (LLViewerJoint*)mRoot.findJoint("mTorso");
+ mChestp = (LLViewerJoint*)mRoot.findJoint("mChest");
+ mNeckp = (LLViewerJoint*)mRoot.findJoint("mNeck");
+ mHeadp = (LLViewerJoint*)mRoot.findJoint("mHead");
+ mSkullp = (LLViewerJoint*)mRoot.findJoint("mSkull");
+ mHipLeftp = (LLViewerJoint*)mRoot.findJoint("mHipLeft");
+ mHipRightp = (LLViewerJoint*)mRoot.findJoint("mHipRight");
+ mKneeLeftp = (LLViewerJoint*)mRoot.findJoint("mKneeLeft");
+ mKneeRightp = (LLViewerJoint*)mRoot.findJoint("mKneeRight");
+ mAnkleLeftp = (LLViewerJoint*)mRoot.findJoint("mAnkleLeft");
+ mAnkleRightp = (LLViewerJoint*)mRoot.findJoint("mAnkleRight");
+ mFootLeftp = (LLViewerJoint*)mRoot.findJoint("mFootLeft");
+ mFootRightp = (LLViewerJoint*)mRoot.findJoint("mFootRight");
+ mWristLeftp = (LLViewerJoint*)mRoot.findJoint("mWristLeft");
+ mWristRightp = (LLViewerJoint*)mRoot.findJoint("mWristRight");
+ mEyeLeftp = (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
+ mEyeRightp = (LLViewerJoint*)mRoot.findJoint("mEyeRight");
+
+ //-------------------------------------------------------------------------
+ // Make sure "well known" pointers exist
+ //-------------------------------------------------------------------------
+ if (!(mPelvisp &&
+ mTorsop &&
+ mChestp &&
+ mNeckp &&
+ mHeadp &&
+ mSkullp &&
+ mHipLeftp &&
+ mHipRightp &&
+ mKneeLeftp &&
+ mKneeRightp &&
+ mAnkleLeftp &&
+ mAnkleRightp &&
+ mFootLeftp &&
+ mFootRightp &&
+ mWristLeftp &&
+ mWristRightp &&
+ mEyeLeftp &&
+ mEyeRightp))
+ {
+ llerrs << "Failed to create avatar." << llendl;
+ return;
+ }
+
+ //-------------------------------------------------------------------------
+ // initialize the pelvis
+ //-------------------------------------------------------------------------
+ mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
+
+ //-------------------------------------------------------------------------
+ // set head offset from pelvis
+ //-------------------------------------------------------------------------
+ updateHeadOffset();
+
+ //-------------------------------------------------------------------------
+ // initialize lip sync morph pointers
+ //-------------------------------------------------------------------------
+ mOohMorph = getVisualParam( "Lipsync_Ooh" );
+ mAahMorph = getVisualParam( "Lipsync_Aah" );
+
+ // If we don't have the Ooh morph, use the Kiss morph
+ if (!mOohMorph)
+ {
+ llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl;
+ mOohMorph = getVisualParam( "Express_Kiss" );
+ }
+
+ // If we don't have the Aah morph, use the Open Mouth morph
+ if (!mAahMorph)
+ {
+ llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl;
+ mAahMorph = getVisualParam( "Express_Open_Mouth" );
+ }
+
+ startDefaultMotions();
+
+ //-------------------------------------------------------------------------
+ // restart any currently active motions
+ //-------------------------------------------------------------------------
+ processAnimationStateChanges();
+
+ mIsBuilt = TRUE;
+ stop_glerror();
+
+ mMeshValid = TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// releaseMeshData()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::releaseMeshData()
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy)
+ {
+ return;
+ }
+
+ //llinfos << "Releasing" << llendl;
+
+ // cleanup mesh data
+ for (std::vector<LLViewerJoint*>::iterator iter = mMeshLOD.begin();
+ iter != mMeshLOD.end();
+ ++iter)
+ {
+ LLViewerJoint* joint = (LLViewerJoint*) *iter;
+ joint->setValid(FALSE, TRUE);
+ }
+
+ //cleanup data
+ if (mDrawable.notNull())
+ {
+ LLFace* facep = mDrawable->getFace(0);
+ facep->setSize(0, 0);
+ for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
+ {
+ facep = mDrawable->getFace(i);
+ facep->setSize(0, 0);
+ }
+ }
+
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (!attachment->getIsHUDAttachment())
+ {
+ attachment->setAttachmentVisibility(FALSE);
+ }
+ }
+ mMeshValid = FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// restoreMeshData()
+//-----------------------------------------------------------------------------
+// virtual
+void LLVOAvatar::restoreMeshData()
+{
+ llassert(!isSelf());
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ //llinfos << "Restoring" << llendl;
+ mMeshValid = TRUE;
+ updateJointLODs();
+
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (!attachment->getIsHUDAttachment())
+ {
+ attachment->setAttachmentVisibility(TRUE);
+ }
+ }
+
+ // force mesh update as LOD might not have changed to trigger this
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+}
+
+//-----------------------------------------------------------------------------
+// updateMeshData()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateMeshData()
+{
+ if (mDrawable.notNull())
+ {
+ stop_glerror();
+
+ S32 f_num = 0 ;
+ const U32 VERTEX_NUMBER_THRESHOLD = 128 ;//small number of this means each part of an avatar has its own vertex buffer.
+ const S32 num_parts = mMeshLOD.size();
+
+ // this order is determined by number of LODS
+ // if a mesh earlier in this list changed LODs while a later mesh doesn't,
+ // the later mesh's index offset will be inaccurate
+ for(S32 part_index = 0 ; part_index < num_parts ;)
+ {
+ S32 j = part_index ;
+ U32 last_v_num = 0, num_vertices = 0 ;
+ U32 last_i_num = 0, num_indices = 0 ;
+
+ while(part_index < num_parts && num_vertices < VERTEX_NUMBER_THRESHOLD)
+ {
+ last_v_num = num_vertices ;
+ last_i_num = num_indices ;
+
+ mMeshLOD[part_index++]->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea);
+ }
+ if(num_vertices < 1)//skip empty meshes
+ {
+ continue ;
+ }
+ if(last_v_num > 0)//put the last inserted part into next vertex buffer.
+ {
+ num_vertices = last_v_num ;
+ num_indices = last_i_num ;
+ part_index-- ;
+ }
+
+ LLFace* facep ;
+ if(f_num < mDrawable->getNumFaces())
+ {
+ facep = mDrawable->getFace(f_num);
+ }
+ else
+ {
+ facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ;
+ }
+
+ // resize immediately
+ facep->setSize(num_vertices, num_indices);
+
+ bool terse_update = false;
+
+ facep->setGeomIndex(0);
+ facep->setIndicesIndex(0);
+
+ LLVertexBuffer* buff = facep->getVertexBuffer();
+ if(!facep->getVertexBuffer())
+ {
+ buff = new LLVertexBufferAvatar();
+ buff->allocateBuffer(num_vertices, num_indices, TRUE);
+ facep->setVertexBuffer(buff);
+ }
+ else
+ {
+ if (buff->getRequestedIndices() == num_indices &&
+ buff->getRequestedVerts() == num_vertices)
+ {
+ terse_update = true;
+ }
+ else
+ {
+ buff->resizeBuffer(num_vertices, num_indices);
+ }
+ }
+
+
+ // This is a hack! Avatars have their own pool, so we are detecting
+ // the case of more than one avatar in the pool (thus > 0 instead of >= 0)
+ if (facep->getGeomIndex() > 0)
+ {
+ llerrs << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << llendl;
+ }
+
+ for(S32 k = j ; k < part_index ; k++)
+ {
+ mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update);
+ }
+
+ stop_glerror();
+ buff->setBuffer(0);
+
+ if(!f_num)
+ {
+ f_num += mNumInitFaces ;
+ }
+ else
+ {
+ f_num++ ;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+// The viewer can only suggest a good size for the agent,
+// the simulator will keep it inside a reasonable range.
+void LLVOAvatar::computeBodySize()
+{
+ LLVector3 pelvis_scale = mPelvisp->getScale();
+
+ // some of the joints have not been cached
+ LLVector3 skull = mSkullp->getPosition();
+ LLVector3 skull_scale = mSkullp->getScale();
+
+ LLVector3 neck = mNeckp->getPosition();
+ LLVector3 neck_scale = mNeckp->getScale();
+
+ LLVector3 chest = mChestp->getPosition();
+ LLVector3 chest_scale = mChestp->getScale();
+
+ // the rest of the joints have been cached
+ LLVector3 head = mHeadp->getPosition();
+ LLVector3 head_scale = mHeadp->getScale();
+
+ LLVector3 torso = mTorsop->getPosition();
+ LLVector3 torso_scale = mTorsop->getScale();
+
+ LLVector3 hip = mHipLeftp->getPosition();
+ LLVector3 hip_scale = mHipLeftp->getScale();
+
+ LLVector3 knee = mKneeLeftp->getPosition();
+ LLVector3 knee_scale = mKneeLeftp->getScale();
+
+ LLVector3 ankle = mAnkleLeftp->getPosition();
+ LLVector3 ankle_scale = mAnkleLeftp->getScale();
+
+ LLVector3 foot = mFootLeftp->getPosition();
+
+ mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
+ knee.mV[VZ] * hip_scale.mV[VZ] -
+ ankle.mV[VZ] * knee_scale.mV[VZ] -
+ foot.mV[VZ] * ankle_scale.mV[VZ];
+
+ LLVector3 new_body_size;
+ new_body_size.mV[VZ] = mPelvisToFoot +
+ // the sqrt(2) correction below is an approximate
+ // correction to get to the top of the head
+ F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
+ head.mV[VZ] * neck_scale.mV[VZ] +
+ neck.mV[VZ] * chest_scale.mV[VZ] +
+ chest.mV[VZ] * torso_scale.mV[VZ] +
+ torso.mV[VZ] * pelvis_scale.mV[VZ];
+
+ // TODO -- measure the real depth and width
+ new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
+ new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
+
+ if (new_body_size != mBodySize)
+ {
+ mBodySize = new_body_size;
+
+ if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
+ { // notify simulator of change in size
+ // but not if we are in the middle of updating appearance
+ gAgent.sendAgentSetAppearance();
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// LLVOAvatar::processUpdateMessage()
+//------------------------------------------------------------------------
+U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
+ void **user_data,
+ U32 block_num, const EObjectUpdateType update_type,
+ LLDataPacker *dp)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ LLVector3 old_vel = getVelocity();
+ const BOOL has_name = !getNVPair("FirstName");
+
+ // Do base class updates...
+ U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
+
+ // Print out arrival information once we have name of avatar.
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (has_name && getNVPair("FirstName"))
+ {
+ mDebugExistenceTimer.reset();
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezArrivedNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl;
+ }
+ }
+ if(retval & LLViewerObject::INVALID_UPDATE)
+ {
+ if (isSelf())
+ {
+ //tell sim to cancel this update
+ gAgent.teleportViaLocation(gAgent.getPositionGlobal());
+ }
+ }
+
+ //llinfos << getRotation() << llendl;
+ //llinfos << getPosition() << llendl;
+
+ return retval;
+}
+
+// virtual
+S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
+{
+ // The core setTETexture() method requests images, so we need
+ // to redirect certain avatar texture requests to different sims.
+ if (isIndexBakedTexture((ETextureIndex)te))
+ {
+ LLHost target_host = getObjectHost();
+ return setTETextureCore(te, uuid, target_host);
+ }
+ else
+ {
+ return setTETextureCore(te, uuid, LLHost::invalid);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar");
+static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints");
+
+//------------------------------------------------------------------------
+// LLVOAvatar::dumpAnimationState()
+//------------------------------------------------------------------------
+void LLVOAvatar::dumpAnimationState()
+{
+ llinfos << "==============================================" << llendl;
+ for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it)
+ {
+ LLUUID id = it->first;
+ std::string playtag = "";
+ if (mPlayingAnimations.find(id) != mPlayingAnimations.end())
+ {
+ playtag = "*";
+ }
+ llinfos << gAnimLibrary.animationName(id) << playtag << llendl;
+ }
+ for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it)
+ {
+ LLUUID id = it->first;
+ bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end();
+ if (!is_signaled)
+ {
+ llinfos << gAnimLibrary.animationName(id) << "!S" << llendl;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// idleUpdate()
+//------------------------------------------------------------------------
+BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+ LLFastTimer t(FTM_AVATAR_UPDATE);
+
+ if (isDead())
+ {
+ llinfos << "Warning! Idle on dead avatar" << llendl;
+ return TRUE;
+ }
+
+ if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
+ {
+ return TRUE;
+ }
+
+ checkTextureLoading() ;
+
+ // force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
+ setPixelAreaAndAngle(gAgent);
+
+ // force asynchronous drawable update
+ if(mDrawable.notNull())
+ {
+ LLFastTimer t(FTM_JOINT_UPDATE);
+
+ if (mIsSitting && getParent())
+ {
+ LLViewerObject *root_object = (LLViewerObject*)getRoot();
+ LLDrawable* drawablep = root_object->mDrawable;
+ // if this object hasn't already been updated by another avatar...
+ if (drawablep) // && !drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ if (root_object->isSelected())
+ {
+ gPipeline.updateMoveNormalAsync(drawablep);
+ }
+ else
+ {
+ gPipeline.updateMoveDampedAsync(drawablep);
+ }
+ }
+ }
+ else
+ {
+ gPipeline.updateMoveDampedAsync(mDrawable);
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // set alpha flag depending on state
+ //--------------------------------------------------------------------
+
+ if (isSelf())
+ {
+ LLViewerObject::idleUpdate(agent, world, time);
+
+ // trigger fidget anims
+ if (isAnyAnimationSignaled(AGENT_STAND_ANIMS, NUM_AGENT_STAND_ANIMS))
+ {
+ agent.fidget();
+ }
+ }
+ else
+ {
+ // Should override the idleUpdate stuff and leave out the angular update part.
+ LLQuaternion rotation = getRotation();
+ LLViewerObject::idleUpdate(agent, world, time);
+ setRotation(rotation);
+ }
+
+ // attach objects that were waiting for a drawable
+ lazyAttach();
+
+ // animate the character
+ // store off last frame's root position to be consistent with camera position
+ LLVector3 root_pos_last = mRoot.getWorldPosition();
+ BOOL detailed_update = updateCharacter(agent);
+
+ static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
+ bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) &&
+ LLVoiceClient::getInstance()->getVoiceEnabled(mID);
+
+ idleUpdateVoiceVisualizer( voice_enabled );
+ idleUpdateMisc( detailed_update );
+ idleUpdateAppearanceAnimation();
+ if (detailed_update)
+ {
+ idleUpdateLipSync( voice_enabled );
+ idleUpdateLoadingEffect();
+ idleUpdateBelowWater(); // wind effect uses this
+ idleUpdateWindEffect();
+ }
+
+ idleUpdateNameTag( root_pos_last );
+ idleUpdateRenderCost();
+
+ return TRUE;
+}
+
+void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
+{
+ bool render_visualizer = voice_enabled;
+
+ // Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
+ if(isSelf())
+ {
+ if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic"))
+ {
+ render_visualizer = false;
+ }
+ }
+
+ mVoiceVisualizer->setVoiceEnabled(render_visualizer);
+
+ if ( voice_enabled )
+ {
+ //----------------------------------------------------------------
+ // Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
+ //----------------------------------------------------------------
+ if( isSelf() )
+ {
+ //----------------------------------------------------------------------------------------
+ // The following takes the voice signal and uses that to trigger gesticulations.
+ //----------------------------------------------------------------------------------------
+ int lastGesticulationLevel = mCurrentGesticulationLevel;
+ mCurrentGesticulationLevel = mVoiceVisualizer->getCurrentGesticulationLevel();
+
+ //---------------------------------------------------------------------------------------------------
+ // If "current gesticulation level" changes, we catch this, and trigger the new gesture
+ //---------------------------------------------------------------------------------------------------
+ if ( lastGesticulationLevel != mCurrentGesticulationLevel )
+ {
+ if ( mCurrentGesticulationLevel != VOICE_GESTICULATION_LEVEL_OFF )
+ {
+ std::string gestureString = "unInitialized";
+ if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; }
+ else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; }
+ else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; }
+ else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; }
+
+ // this is the call that Karl S. created for triggering gestures from within the code.
+ LLGestureMgr::instance().triggerAndReviseString( gestureString );
+ }
+ }
+
+ } //if( isSelf() )
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer.
+ // Also, here we trigger voice visualizer start and stop speaking, so it can animate the voice symbol.
+ //
+ // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been
+ // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.
+ //-----------------------------------------------------------------------------------------------------------------
+ if (LLVoiceClient::getInstance()->getIsSpeaking( mID ))
+ {
+ if (!mVoiceVisualizer->getCurrentlySpeaking())
+ {
+ mVoiceVisualizer->setStartSpeaking();
+
+ //printf( "gAwayTimer.reset();\n" );
+ }
+
+ mVoiceVisualizer->setSpeakingAmplitude( LLVoiceClient::getInstance()->getCurrentPower( mID ) );
+
+ if( isSelf() )
+ {
+ gAgent.clearAFK();
+ }
+ }
+ else
+ {
+ if ( mVoiceVisualizer->getCurrentlySpeaking() )
+ {
+ mVoiceVisualizer->setStopSpeaking();
+
+ if ( mLipSyncActive )
+ {
+ if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE);
+ if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE);
+
+ mLipSyncActive = false;
+ LLCharacter::updateVisualParams();
+ dirtyMesh();
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------------------------
+ // here we get the approximate head position and set as sound source for the voice symbol
+ // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
+ //--------------------------------------------------------------------------------------------
+
+ if ( mIsSitting )
+ {
+ LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
+ mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
+ }
+ else
+ {
+ LLVector3 tagPos = mRoot.getWorldPosition();
+ tagPos[VZ] -= mPelvisToFoot;
+ tagPos[VZ] += ( mBodySize[VZ] + 0.125f );
+ mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );
+ }
+ }//if ( voiceEnabled )
+}
+
+static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments");
+
+void LLVOAvatar::idleUpdateMisc(bool detailed_update)
+{
+ if (LLVOAvatar::sJointDebug)
+ {
+ llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl;
+ }
+
+ LLJoint::sNumUpdates = 0;
+ LLJoint::sNumTouches = 0;
+
+ BOOL visible = isVisible() || mNeedsAnimUpdate;
+
+ // update attachments positions
+ if (detailed_update || !sUseImpostors)
+ {
+ LLFastTimer t(FTM_ATTACHMENT_UPDATE);
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ LLViewerObject* attached_object = (*attachment_iter);
+ BOOL visibleAttachment = visible || (attached_object &&
+ !(attached_object->mDrawable->getSpatialBridge() &&
+ attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
+
+ if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid())
+ {
+ // if selecting any attachments, update all of them as non-damped
+ if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment())
+ {
+ gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
+ }
+ else
+ {
+ gPipeline.updateMoveDampedAsync(attached_object->mDrawable);
+ }
+
+ LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
+ if (bridge)
+ {
+ gPipeline.updateMoveNormalAsync(bridge);
+ }
+ attached_object->updateText();
+ }
+ }
+ }
+ }
+
+ mNeedsAnimUpdate = FALSE;
+
+ if (isImpostor() && !mNeedsImpostorUpdate)
+ {
+ LLVector4a ext[2];
+ F32 distance;
+ LLVector3 angle;
+
+ getImpostorValues(ext, angle, distance);
+
+ for (U32 i = 0; i < 3 && !mNeedsImpostorUpdate; i++)
+ {
+ F32 cur_angle = angle.mV[i];
+ F32 old_angle = mImpostorAngle.mV[i];
+ F32 angle_diff = fabsf(cur_angle-old_angle);
+
+ if (angle_diff > F_PI/512.f*distance*mUpdatePeriod)
+ {
+ mNeedsImpostorUpdate = TRUE;
+ }
+ }
+
+ if (detailed_update && !mNeedsImpostorUpdate)
+ { //update impostor if view angle, distance, or bounding box change
+ //significantly
+
+ F32 dist_diff = fabsf(distance-mImpostorDistance);
+ if (dist_diff/mImpostorDistance > 0.1f)
+ {
+ mNeedsImpostorUpdate = TRUE;
+ }
+ else
+ {
+ //VECTORIZE THIS
+ getSpatialExtents(ext[0], ext[1]);
+ LLVector4a diff;
+ diff.setSub(ext[1], mImpostorExtents[1]);
+ if (diff.getLength3().getF32() > 0.05f)
+ {
+ mNeedsImpostorUpdate = TRUE;
+ }
+ else
+ {
+ diff.setSub(ext[0], mImpostorExtents[0]);
+ if (diff.getLength3().getF32() > 0.05f)
+ {
+ mNeedsImpostorUpdate = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ mDrawable->movePartition();
+
+ //force a move if sitting on an active object
+ if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
+ {
+ gPipeline.markMoved(mDrawable, TRUE);
+ }
+}
+
+void LLVOAvatar::idleUpdateAppearanceAnimation()
+{
+ // update morphing params
+ if (mAppearanceAnimating)
+ {
+ ESex avatar_sex = getSex();
+ F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32();
+ if (appearance_anim_time >= APPEARANCE_MORPH_TIME)
+ {
+ mAppearanceAnimating = FALSE;
+ for (LLVisualParam *param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ if (param->isTweakable())
+ {
+ param->stopAnimating(FALSE);
+ }
+ }
+ updateVisualParams();
+ if (isSelf())
+ {
+ gAgent.sendAgentSetAppearance();
+ }
+ }
+ else
+ {
+ F32 morph_amt = calcMorphAmount();
+ LLVisualParam *param;
+
+ if (!isSelf())
+ {
+ // animate only top level params for non-self avatars
+ for (param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ if (param->isTweakable())
+ {
+ param->animate(morph_amt, FALSE);
+ }
+ }
+ }
+
+ // apply all params
+ for (param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ param->apply(avatar_sex);
+ }
+
+ mLastAppearanceBlendTime = appearance_anim_time;
+ }
+ dirtyMesh();
+ }
+}
+
+F32 LLVOAvatar::calcMorphAmount()
+{
+ F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32();
+ F32 blend_frac = calc_bouncy_animation(appearance_anim_time / APPEARANCE_MORPH_TIME);
+ F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / APPEARANCE_MORPH_TIME);
+
+ F32 morph_amt;
+ if (last_blend_frac == 1.f)
+ {
+ morph_amt = 1.f;
+ }
+ else
+ {
+ morph_amt = (blend_frac - last_blend_frac) / (1.f - last_blend_frac);
+ }
+
+ return morph_amt;
+}
+
+void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
+{
+ // Use the Lipsync_Ooh and Lipsync_Aah morphs for lip sync
+ if ( voice_enabled && (LLVoiceClient::getInstance()->lipSyncEnabled()) && LLVoiceClient::getInstance()->getIsSpeaking( mID ) )
+ {
+ F32 ooh_morph_amount = 0.0f;
+ F32 aah_morph_amount = 0.0f;
+
+ mVoiceVisualizer->lipSyncOohAah( ooh_morph_amount, aah_morph_amount );
+
+ if( mOohMorph )
+ {
+ F32 ooh_weight = mOohMorph->getMinWeight()
+ + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight());
+
+ mOohMorph->setWeight( ooh_weight, FALSE );
+ }
+
+ if( mAahMorph )
+ {
+ F32 aah_weight = mAahMorph->getMinWeight()
+ + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight());
+
+ mAahMorph->setWeight( aah_weight, FALSE );
+ }
+
+ mLipSyncActive = true;
+ LLCharacter::updateVisualParams();
+ dirtyMesh();
+ }
+}
+
+void LLVOAvatar::idleUpdateLoadingEffect()
+{
+ // update visibility when avatar is partially loaded
+ if (updateIsFullyLoaded()) // changed?
+ {
+ if (isFullyLoaded() && isSelf())
+ {
+ static bool first_fully_visible = true;
+ if (first_fully_visible)
+ {
+ llinfos << "self isFullyLoaded, first_fully_visible" << llendl;
+
+ first_fully_visible = false;
+ LLAppearanceMgr::instance().onFirstFullyVisible();
+ }
+ }
+ if (isFullyLoaded())
+ {
+ deleteParticleSource();
+ updateLOD();
+ }
+ else
+ {
+ LLPartSysData particle_parameters;
+
+ // fancy particle cloud designed by Brent
+ particle_parameters.mPartData.mMaxAge = 4.f;
+ particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
+ particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
+ particle_parameters.mPartData.mStartScale.mV[VY] = 1.0f;
+ particle_parameters.mPartData.mEndScale.mV[VX] = 0.02f;
+ particle_parameters.mPartData.mEndScale.mV[VY] = 0.02f;
+ particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f);
+ particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f);
+ particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
+ LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
+ particle_parameters.mPartImageID = cloud->getID();
+ particle_parameters.mMaxAge = 0.f;
+ particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;
+ particle_parameters.mInnerAngle = F_PI;
+ particle_parameters.mOuterAngle = 0.f;
+ particle_parameters.mBurstRate = 0.02f;
+ particle_parameters.mBurstRadius = 0.0f;
+ particle_parameters.mBurstPartCount = 1;
+ particle_parameters.mBurstSpeedMin = 0.1f;
+ particle_parameters.mBurstSpeedMax = 1.f;
+ particle_parameters.mPartData.mFlags = ( LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
+ LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |
+ LLPartData::LL_PART_TARGET_POS_MASK );
+
+ setParticleSource(particle_parameters, getID());
+ }
+ }
+}
+
+void LLVOAvatar::idleUpdateWindEffect()
+{
+ // update wind effect
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH))
+ {
+ F32 hover_strength = 0.f;
+ F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast;
+ mRippleTimeLast = mRippleTimer.getElapsedTimeF32();
+ LLVector3 velocity = getVelocity();
+ F32 speed = velocity.length();
+ //RN: velocity varies too much frame to frame for this to work
+ mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLCriticalDamp::getInterpolant(0.02f));
+ mLastVel = velocity;
+ LLVector4 wind;
+ wind.setVec(getRegion()->mWind.getVelocityNoisy(getPositionAgent(), 4.f) - velocity);
+
+ if (mInAir)
+ {
+ hover_strength = HOVER_EFFECT_STRENGTH * llmax(0.f, HOVER_EFFECT_MAX_SPEED - speed);
+ }
+
+ if (mBelowWater)
+ {
+ // TODO: make cloth flow more gracefully when underwater
+ hover_strength += UNDERWATER_EFFECT_STRENGTH;
+ }
+
+ wind.mV[VZ] += hover_strength;
+ wind.normalize();
+
+ wind.mV[VW] = llmin(0.025f + (speed * 0.015f) + hover_strength, 0.5f);
+ F32 interp;
+ if (wind.mV[VW] > mWindVec.mV[VW])
+ {
+ interp = LLCriticalDamp::getInterpolant(0.2f);
+ }
+ else
+ {
+ interp = LLCriticalDamp::getInterpolant(0.4f);
+ }
+ mWindVec = lerp(mWindVec, wind, interp);
+
+ F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f);
+ mWindFreq = lerp(mWindFreq, wind_freq, interp);
+
+ if (mBelowWater)
+ {
+ mWindFreq *= UNDERWATER_FREQUENCY_DAMP;
+ }
+
+ mRipplePhase += (time_delta * mWindFreq);
+ if (mRipplePhase > F_TWO_PI)
+ {
+ mRipplePhase = fmodf(mRipplePhase, F_TWO_PI);
+ }
+ }
+}
+
+void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
+{
+ // update chat bubble
+ //--------------------------------------------------------------------
+ // draw text label over character's head
+ //--------------------------------------------------------------------
+ if (mChatTimer.getElapsedTimeF32() > BUBBLE_CHAT_TIME)
+ {
+ mChats.clear();
+ }
+
+ const F32 time_visible = mTimeVisible.getElapsedTimeF32();
+ const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime"); // seconds
+ const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
+ BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
+ BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
+ BOOL render_name = visible_chat ||
+ (visible_avatar &&
+ ((sRenderName == RENDER_NAME_ALWAYS) ||
+ (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
+ // If it's your own avatar, don't draw in mouselook, and don't
+ // draw if we're specifically hiding our own name.
+ if (isSelf())
+ {
+ render_name = render_name
+ && !gAgentCamera.cameraMouselook()
+ && (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf")
+ && gSavedSettings.getS32("AvatarNameTagMode") ));
+ }
+
+ if ( !render_name )
+ {
+ if (mNameText)
+ {
+ // ...clean up old name tag
+ mNameText->markDead();
+ mNameText = NULL;
+ sNumVisibleChatBubbles--;
+ }
+ return;
+ }
+
+ BOOL new_name = FALSE;
+ if (visible_chat != mVisibleChat)
+ {
+ mVisibleChat = visible_chat;
+ new_name = TRUE;
+ }
+
+ if (sRenderGroupTitles != mRenderGroupTitles)
+ {
+ mRenderGroupTitles = sRenderGroupTitles;
+ new_name = TRUE;
+ }
+
+ // First Calculate Alpha
+ // If alpha > 0, create mNameText if necessary, otherwise delete it
+ F32 alpha = 0.f;
+ if (mAppAngle > 5.f)
+ {
+ const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION;
+ if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME)
+ {
+ alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION;
+ }
+ else
+ {
+ // ...not fading, full alpha
+ alpha = 1.f;
+ }
+ }
+ else if (mAppAngle > 2.f)
+ {
+ // far away is faded out also
+ alpha = (mAppAngle-2.f)/3.f;
+ }
+
+ if (alpha <= 0.f)
+ {
+ if (mNameText)
+ {
+ mNameText->markDead();
+ mNameText = NULL;
+ sNumVisibleChatBubbles--;
+ }
+ return;
+ }
+
+ if (!mNameText)
+ {
+ mNameText = static_cast<LLHUDNameTag*>( LLHUDObject::addHUDObject(
+ LLHUDObject::LL_HUD_NAME_TAG) );
+ //mNameText->setMass(10.f);
+ mNameText->setSourceObject(this);
+ mNameText->setVertAlignment(LLHUDNameTag::ALIGN_VERT_TOP);
+ mNameText->setVisibleOffScreen(TRUE);
+ mNameText->setMaxLines(11);
+ mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
+ sNumVisibleChatBubbles++;
+ new_name = TRUE;
+ }
+
+ LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last);
+ mNameText->setPositionAgent(name_position);
+ idleUpdateNameTagText(new_name);
+ idleUpdateNameTagAlpha(new_name, alpha);
+}
+
+void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
+ {
+ LLNameValue *title = getNVPair("Title");
+ LLNameValue* firstname = getNVPair("FirstName");
+ LLNameValue* lastname = getNVPair("LastName");
+
+ // Avatars must have a first and last name
+ if (!firstname || !lastname) return;
+
+ bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end();
+ bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end();
+ bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end();
+ bool is_muted;
+ if (isSelf())
+ {
+ is_muted = false;
+ }
+ else
+ {
+ is_muted = LLMuteList::getInstance()->isMuted(getID());
+ }
+ bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
+ bool is_cloud = getIsCloud();
+
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (is_appearance != mNameAppearance)
+ {
+ if (is_appearance)
+ {
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl;
+ }
+ else
+ {
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args);
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl;
+ }
+ }
+ }
+
+ // Rebuild name tag if state change detected
+ if (mNameString.empty()
+ || new_name
+ || (!title && !mTitle.empty())
+ || (title && mTitle != title->getString())
+ || is_away != mNameAway
+ || is_busy != mNameBusy
+ || is_muted != mNameMute
+ || is_appearance != mNameAppearance
+ || is_friend != mNameFriend
+ || is_cloud != mNameCloud)
+ {
+ LLColor4 name_tag_color = getNameTagColor(is_friend);
+
+ clearNameTag();
+
+ if (is_away || is_muted || is_busy || is_appearance)
+ {
+ std::string line;
+ if (is_away)
+ {
+ line += LLTrans::getString("AvatarAway");
+ line += ", ";
+ }
+ if (is_busy)
+ {
+ line += LLTrans::getString("AvatarBusy");
+ line += ", ";
+ }
+ if (is_muted)
+ {
+ line += LLTrans::getString("AvatarMuted");
+ line += ", ";
+ }
+ if (is_appearance)
+ {
+ line += LLTrans::getString("AvatarEditingAppearance");
+ line += ", ";
+ }
+ if (is_cloud)
+ {
+ line += LLTrans::getString("LoadingData");
+ line += ", ";
+ }
+ // trim last ", "
+ line.resize( line.length() - 2 );
+ addNameTagLine(line, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
+ }
+
+ if (sRenderGroupTitles
+ && title && title->getString() && title->getString()[0] != '\0')
+ {
+ std::string title_str = title->getString();
+ LLStringFn::replace_ascii_controlchars(title_str,LL_UNKNOWN_CHAR);
+ addNameTagLine(title_str, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
+ }
+
+ static LLUICachedControl<bool> show_display_names("NameTagShowDisplayNames");
+ static LLUICachedControl<bool> show_usernames("NameTagShowUsernames");
+
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(getID(), &av_name))
+ {
+ // ...call this function back when the name arrives
+ // and force a rebuild
+ LLAvatarNameCache::get(getID(),
+ boost::bind(&LLVOAvatar::clearNameTag, this));
+ }
+
+ // Might be blank if name not available yet, that's OK
+ if (show_display_names)
+ {
+ addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerif());
+ }
+ // Suppress SLID display if display name matches exactly (ugh)
+ if (show_usernames && !av_name.mIsDisplayNameDefault)
+ {
+ // *HACK: Desaturate the color
+ LLColor4 username_color = name_tag_color * 0.83f;
+ addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL,
+ LLFontGL::getFontSansSerifSmall());
+ }
+ }
+ else
+ {
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ std::string full_name =
+ LLCacheName::buildFullName( firstname->getString(), lastname->getString() );
+ addNameTagLine(full_name, name_tag_color, LLFontGL::NORMAL, font);
+ }
+
+ mNameAway = is_away;
+ mNameBusy = is_busy;
+ mNameMute = is_muted;
+ mNameAppearance = is_appearance;
+ mNameFriend = is_friend;
+ mNameCloud = is_cloud;
+ mTitle = title ? title->getString() : "";
+ LLStringFn::replace_ascii_controlchars(mTitle,LL_UNKNOWN_CHAR);
+ new_name = TRUE;
+ }
+
+ if (mVisibleChat)
+ {
+ mNameText->setFont(LLFontGL::getFontSansSerif());
+ mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT);
+ mNameText->setFadeDistance(CHAT_NORMAL_RADIUS * 2.f, 5.f);
+
+ char line[MAX_STRING]; /* Flawfinder: ignore */
+ line[0] = '\0';
+ std::deque<LLChat>::iterator chat_iter = mChats.begin();
+ mNameText->clearString();
+
+ LLColor4 new_chat = LLUIColorTable::instance().getColor( isSelf() ? "UserChatColor" : "AgentChatColor" );
+ LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f);
+ LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f);
+ if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES)
+ {
+ ++chat_iter;
+ }
+
+ for(; chat_iter != mChats.end(); ++chat_iter)
+ {
+ F32 chat_fade_amt = llclamp((F32)((LLFrameTimer::getElapsedSeconds() - chat_iter->mTime) / CHAT_FADE_TIME), 0.f, 4.f);
+ LLFontGL::StyleFlags style;
+ switch(chat_iter->mChatType)
+ {
+ case CHAT_TYPE_WHISPER:
+ style = LLFontGL::ITALIC;
+ break;
+ case CHAT_TYPE_SHOUT:
+ style = LLFontGL::BOLD;
+ break;
+ default:
+ style = LLFontGL::NORMAL;
+ break;
+ }
+ if (chat_fade_amt < 1.f)
+ {
+ F32 u = clamp_rescale(chat_fade_amt, 0.9f, 1.f, 0.f, 1.f);
+ mNameText->addLine(chat_iter->mText, lerp(new_chat, normal_chat, u), style);
+ }
+ else if (chat_fade_amt < 2.f)
+ {
+ F32 u = clamp_rescale(chat_fade_amt, 1.9f, 2.f, 0.f, 1.f);
+ mNameText->addLine(chat_iter->mText, lerp(normal_chat, old_chat, u), style);
+ }
+ else if (chat_fade_amt < 3.f)
+ {
+ // *NOTE: only remove lines down to minimum number
+ mNameText->addLine(chat_iter->mText, old_chat, style);
+ }
+ }
+ mNameText->setVisibleOffScreen(TRUE);
+
+ if (mTyping)
+ {
+ S32 dot_count = (llfloor(mTypingTimer.getElapsedTimeF32() * 3.f) + 2) % 3 + 1;
+ switch(dot_count)
+ {
+ case 1:
+ mNameText->addLine(".", new_chat);
+ break;
+ case 2:
+ mNameText->addLine("..", new_chat);
+ break;
+ case 3:
+ mNameText->addLine("...", new_chat);
+ break;
+ }
+
+ }
+ }
+ else
+ {
+ // ...not using chat bubbles, just names
+ mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_CENTER);
+ mNameText->setFadeDistance(CHAT_NORMAL_RADIUS, 5.f);
+ mNameText->setVisibleOffScreen(FALSE);
+ }
+}
+
+void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font)
+{
+ llassert(mNameText);
+ if (mVisibleChat)
+ {
+ mNameText->addLabel(line);
+ }
+ else
+ {
+ mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font);
+ }
+ mNameString += line;
+ mNameString += '\n';
+}
+
+void LLVOAvatar::clearNameTag()
+{
+ mNameString.clear();
+ if (mNameText)
+ {
+ mNameText->setLabel("");
+ mNameText->setString( "" );
+ }
+}
+
+//static
+void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id)
+{
+ LLViewerObject* obj = gObjectList.findObject(agent_id);
+ if (!obj) return;
+
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(obj);
+ if (!avatar) return;
+
+ avatar->clearNameTag();
+}
+
+//static
+void LLVOAvatar::invalidateNameTags()
+{
+ std::vector<LLCharacter*>::iterator it = LLCharacter::sInstances.begin();
+ for ( ; it != LLCharacter::sInstances.end(); ++it)
+ {
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*it);
+ if (!avatar) continue;
+ if (avatar->isDead()) continue;
+
+ avatar->clearNameTag();
+
+ }
+}
+
+// Compute name tag position during idle update
+LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
+{
+ LLQuaternion root_rot = mRoot.getWorldRotation();
+ LLVector3 pixel_right_vec;
+ LLVector3 pixel_up_vec;
+ LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec);
+ LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin();
+ camera_to_av.normalize();
+ LLVector3 local_camera_at = camera_to_av * ~root_rot;
+ LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis();
+ local_camera_up.normalize();
+ local_camera_up = local_camera_up * ~root_rot;
+
+ local_camera_up.scaleVec(mBodySize * 0.5f);
+ local_camera_at.scaleVec(mBodySize * 0.5f);
+
+ LLVector3 name_position = mRoot.getWorldPosition();
+ name_position[VZ] -= mPelvisToFoot;
+ name_position[VZ] += (mBodySize[VZ]* 0.55f);
+ name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av));
+ name_position += pixel_up_vec * 15.f;
+
+ return name_position;
+}
+
+void LLVOAvatar::idleUpdateNameTagAlpha(BOOL new_name, F32 alpha)
+{
+ llassert(mNameText);
+
+ if (new_name
+ || alpha != mNameAlpha)
+ {
+ mNameText->setAlpha(alpha);
+ mNameAlpha = alpha;
+ }
+}
+
+LLColor4 LLVOAvatar::getNameTagColor(bool is_friend)
+{
+ static LLUICachedControl<bool> show_friends("NameTagShowFriends");
+ const char* color_name;
+ if (show_friends && is_friend)
+ {
+ color_name = "NameTagFriend";
+ }
+ else if (LLAvatarNameCache::useDisplayNames())
+ {
+ // ...color based on whether username "matches" a computed display
+ // name
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(getID(), &av_name)
+ && av_name.mIsDisplayNameDefault)
+ {
+ color_name = "NameTagMatch";
+ }
+ else
+ {
+ color_name = "NameTagMismatch";
+ }
+ }
+ else
+ {
+ // ...not using display names
+ color_name = "NameTagLegacy";
+ }
+ return LLUIColorTable::getInstance()->getColor( color_name );
+}
+
+void LLVOAvatar::idleUpdateBelowWater()
+{
+ F32 avatar_height = (F32)(getPositionGlobal().mdV[VZ]);
+
+ F32 water_height;
+ water_height = getRegion()->getWaterHeight();
+
+ mBelowWater = avatar_height < water_height;
+}
+
+void LLVOAvatar::slamPosition()
+{
+ gAgent.setPositionAgent(getPositionAgent());
+ mRoot.setWorldPosition(getPositionAgent()); // teleport
+ setChanged(TRANSLATED);
+ if (mDrawable.notNull())
+ {
+ gPipeline.updateMoveNormalAsync(mDrawable);
+ }
+ mRoot.updateWorldMatrixChildren();
+}
+
+//------------------------------------------------------------------------
+// updateCharacter()
+// called on both your avatar and other avatars
+//------------------------------------------------------------------------
+BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ // clear debug text
+ mDebugText.clear();
+ if (LLVOAvatar::sShowAnimationDebug)
+ {
+ for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
+ iter != mMotionController.getActiveMotions().end(); ++iter)
+ {
+ LLMotion* motionp = *iter;
+ if (motionp->getMinPixelArea() < getPixelArea())
+ {
+ std::string output;
+ if (motionp->getName().empty())
+ {
+ output = llformat("%s - %d",
+ gAgent.isGodlikeWithoutAdminMenuFakery() ?
+ motionp->getID().asString().c_str() :
+ LLUUID::null.asString().c_str(),
+ (U32)motionp->getPriority());
+ }
+ else
+ {
+ output = llformat("%s - %d",
+ motionp->getName().c_str(),
+ (U32)motionp->getPriority());
+ }
+ addDebugText(output);
+ }
+ }
+ }
+
+ LLVector3d root_pos_global;
+
+ if (!mIsBuilt)
+ {
+ return FALSE;
+ }
+
+ BOOL visible = isVisible();
+
+ // For fading out the names above heads, only let the timer
+ // run if we're visible.
+ if (mDrawable.notNull() && !visible)
+ {
+ mTimeVisible.reset();
+ }
+
+
+ //--------------------------------------------------------------------
+ // the rest should only be done occasionally for far away avatars
+ //--------------------------------------------------------------------
+
+ if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
+ {
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+ LLVector4a size;
+ size.setSub(ext[1],ext[0]);
+ F32 mag = size.getLength3().getF32()*0.5f;
+
+ F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
+ if (LLMuteList::getInstance()->isMuted(getID()))
+ { // muted avatars update at 16 hz
+ mUpdatePeriod = 16;
+ }
+ else if (mVisibilityRank <= LLVOAvatar::sMaxVisible ||
+ mDrawable->mDistanceWRTCamera < 1.f + mag)
+ { //first 25% of max visible avatars are not impostored
+ //also, don't impostor avatars whose bounding box may be penetrating the
+ //impostor camera near clip plane
+ mUpdatePeriod = 1;
+ }
+ else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4)
+ { //background avatars are REALLY slow updating impostors
+ mUpdatePeriod = 16;
+ }
+ else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3)
+ { //back 25% of max visible avatars are slow updating impostors
+ mUpdatePeriod = 8;
+ }
+ else if (mImpostorPixelArea <= impostor_area)
+ { // stuff in between gets an update period based on pixel area
+ mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8);
+ }
+ else
+ {
+ //nearby avatars, update the impostors more frequently.
+ mUpdatePeriod = 4;
+ }
+
+ visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
+ }
+
+ // don't early out for your own avatar, as we rely on your animations playing reliably
+ // for example, the "turn around" animation when entering customize avatar needs to trigger
+ // even when your avatar is offscreen
+ if (!visible && !isSelf())
+ {
+ updateMotions(LLCharacter::HIDDEN_UPDATE);
+ return FALSE;
+ }
+
+ // change animation time quanta based on avatar render load
+ if (!isSelf() && !mIsDummy)
+ {
+ F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);
+ F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);
+ F32 time_step = time_quantum * pixel_area_scale;
+ if (time_step != 0.f)
+ {
+ // disable walk motion servo controller as it doesn't work with motion timesteps
+ stopMotion(ANIM_AGENT_WALK_ADJUST);
+ removeAnimationData("Walk Speed");
+ }
+ mMotionController.setTimeStep(time_step);
+// llinfos << "Setting timestep to " << time_quantum * pixel_area_scale << llendl;
+ }
+
+ if (getParent() && !mIsSitting)
+ {
+ sitOnObject((LLViewerObject*)getParent());
+ }
+ else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
+ {
+ getOffObject();
+ }
+
+ //--------------------------------------------------------------------
+ // create local variables in world coords for region position values
+ //--------------------------------------------------------------------
+ F32 speed;
+ LLVector3 normal;
+
+ LLVector3 xyVel = getVelocity();
+ xyVel.mV[VZ] = 0.0f;
+ speed = xyVel.length();
+
+ BOOL throttle = TRUE;
+
+ if (!(mIsSitting && getParent()))
+ {
+ //--------------------------------------------------------------------
+ // get timing info
+ // handle initial condition case
+ //--------------------------------------------------------------------
+ F32 animation_time = mAnimTimer.getElapsedTimeF32();
+ if (mTimeLast == 0.0f)
+ {
+ mTimeLast = animation_time;
+ throttle = FALSE;
+
+ // put the pelvis at slaved position/mRotation
+ mRoot.setWorldPosition( getPositionAgent() ); // first frame
+ mRoot.setWorldRotation( getRotation() );
+ }
+
+ //--------------------------------------------------------------------
+ // dont' let dT get larger than 1/5th of a second
+ //--------------------------------------------------------------------
+ F32 deltaTime = animation_time - mTimeLast;
+
+ deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX );
+ mTimeLast = animation_time;
+
+ mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f);
+
+ //--------------------------------------------------------------------
+ // compute the position of the avatar's root
+ //--------------------------------------------------------------------
+ LLVector3d root_pos;
+ LLVector3d ground_under_pelvis;
+
+ if (isSelf())
+ {
+ gAgent.setPositionAgent(getRenderPosition());
+ }
+
+ root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());
+
+ resolveHeightGlobal(root_pos, ground_under_pelvis, normal);
+ F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);
+ BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||
+ foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE);
+
+ if (in_air && !mInAir)
+ {
+ mTimeInAir.reset();
+ }
+ mInAir = in_air;
+
+ // correct for the fact that the pelvis is not necessarily the center
+ // of the agent's physical representation
+ root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot;
+
+ LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
+
+ if (newPosition != mRoot.getXform()->getWorldPosition())
+ {
+ mRoot.touch();
+ mRoot.setWorldPosition( newPosition ); // regular update
+ }
+
+
+ //--------------------------------------------------------------------
+ // Propagate viewer object rotation to root of avatar
+ //--------------------------------------------------------------------
+ if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
+ {
+ LLQuaternion iQ;
+ LLVector3 upDir( 0.0f, 0.0f, 1.0f );
+
+ // Compute a forward direction vector derived from the primitive rotation
+ // and the velocity vector. When walking or jumping, don't let body deviate
+ // more than 90 from the view, if necessary, flip the velocity vector.
+
+ LLVector3 primDir;
+ if (isSelf())
+ {
+ primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector());
+ primDir.normalize();
+ }
+ else
+ {
+ primDir = getRotation().getMatrix3().getFwdRow();
+ }
+ LLVector3 velDir = getVelocity();
+ velDir.normalize();
+ if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())
+ {
+ F32 vpD = velDir * primDir;
+ if (vpD < -0.5f)
+ {
+ velDir *= -1.0f;
+ }
+ }
+ LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f));
+ if (isSelf() && gAgentCamera.cameraMouselook())
+ {
+ // make sure fwdDir stays in same general direction as primdir
+ if (gAgent.getFlying())
+ {
+ fwdDir = LLViewerCamera::getInstance()->getAtAxis();
+ }
+ else
+ {
+ LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ LLVector3 up_vector = gAgent.getReferenceUpVector();
+ at_axis -= up_vector * (at_axis * up_vector);
+ at_axis.normalize();
+
+ F32 dot = fwdDir * at_axis;
+ if (dot < 0.f)
+ {
+ fwdDir -= 2.f * at_axis * dot;
+ fwdDir.normalize();
+ }
+ }
+
+ }
+
+ LLQuaternion root_rotation = mRoot.getWorldMatrix().quaternion();
+ F32 root_roll, root_pitch, root_yaw;
+ root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
+
+ // When moving very slow, the pelvis is allowed to deviate from the
+ // forward direction to allow it to hold it's position while the torso
+ // and head turn. Once in motion, it must conform however.
+ BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
+
+ LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV );
+ F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, PELVIS_ROT_THRESHOLD_SLOW, PELVIS_ROT_THRESHOLD_FAST);
+
+ if (self_in_mouselook)
+ {
+ pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR;
+ }
+ pelvis_rot_threshold *= DEG_TO_RAD;
+
+ F32 angle = angle_between( pelvisDir, fwdDir );
+
+ // The avatar's root is allowed to have a yaw that deviates widely
+ // from the forward direction, but if roll or pitch are off even
+ // a little bit we need to correct the rotation.
+ if(root_roll < 1.f * DEG_TO_RAD
+ && root_pitch < 5.f * DEG_TO_RAD)
+ {
+ // smaller correction vector means pelvis follows prim direction more closely
+ if (!mTurning && angle > pelvis_rot_threshold*0.75f)
+ {
+ mTurning = TRUE;
+ }
+
+ // use tighter threshold when turning
+ if (mTurning)
+ {
+ pelvis_rot_threshold *= 0.4f;
+ }
+
+ // am I done turning?
+ if (angle < pelvis_rot_threshold)
+ {
+ mTurning = FALSE;
+ }
+
+ LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f);
+ fwdDir += correction_vector;
+ }
+ else
+ {
+ mTurning = FALSE;
+ }
+
+ // Now compute the full world space rotation for the whole body (wQv)
+ LLVector3 leftDir = upDir % fwdDir;
+ leftDir.normalize();
+ fwdDir = leftDir % upDir;
+ LLQuaternion wQv( fwdDir, leftDir, upDir );
+
+ if (isSelf() && mTurning)
+ {
+ if ((fwdDir % pelvisDir) * upDir > 0.f)
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT);
+ }
+ else
+ {
+ gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT);
+ }
+ }
+
+ // Set the root rotation, but do so incrementally so that it
+ // lags in time by some fixed amount.
+ //F32 u = LLCriticalDamp::getInterpolant(PELVIS_LAG);
+ F32 pelvis_lag_time = 0.f;
+ if (self_in_mouselook)
+ {
+ pelvis_lag_time = PELVIS_LAG_MOUSELOOK;
+ }
+ else if (mInAir)
+ {
+ pelvis_lag_time = PELVIS_LAG_FLYING;
+ // increase pelvis lag time when moving slowly
+ pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f);
+ }
+ else
+ {
+ pelvis_lag_time = PELVIS_LAG_WALKING;
+ }
+
+ F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);
+
+ mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) );
+
+ }
+ }
+ else if (mDrawable.notNull())
+ {
+ mRoot.setPosition(mDrawable->getPosition());
+ mRoot.setRotation(mDrawable->getRotation());
+ }
+
+ //-------------------------------------------------------------------------
+ // Update character motions
+ //-------------------------------------------------------------------------
+ // store data relevant to motions
+ mSpeed = speed;
+
+ // update animations
+ if (mSpecialRenderMode == 1) // Animation Preview
+ updateMotions(LLCharacter::FORCE_UPDATE);
+ else
+ updateMotions(LLCharacter::NORMAL_UPDATE);
+
+ // update head position
+ updateHeadOffset();
+
+ //-------------------------------------------------------------------------
+ // Find the ground under each foot, these are used for a variety
+ // of things that follow
+ //-------------------------------------------------------------------------
+ LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
+
+ LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
+ LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
+ resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
+ resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
+
+ F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
+ F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
+
+ if (!mIsSitting)
+ {
+ //-------------------------------------------------------------------------
+ // Figure out which foot is on ground
+ //-------------------------------------------------------------------------
+ if (!mInAir)
+ {
+ if ((leftElev < 0.0f) || (rightElev < 0.0f))
+ {
+ ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ ankle_right_pos_agent = mFootRightp->getWorldPosition();
+ leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
+ rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
+ }
+ }
+ }
+
+ //-------------------------------------------------------------------------
+ // Generate footstep sounds when feet hit the ground
+ //-------------------------------------------------------------------------
+ const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
+ const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
+
+ if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
+ {
+ BOOL playSound = FALSE;
+ LLVector3 foot_pos_agent;
+
+ BOOL onGroundLeft = (leftElev <= 0.05f);
+ BOOL onGroundRight = (rightElev <= 0.05f);
+
+ // did left foot hit the ground?
+ if ( onGroundLeft && !mWasOnGroundLeft )
+ {
+ foot_pos_agent = ankle_left_pos_agent;
+ playSound = TRUE;
+ }
+
+ // did right foot hit the ground?
+ if ( onGroundRight && !mWasOnGroundRight )
+ {
+ foot_pos_agent = ankle_right_pos_agent;
+ playSound = TRUE;
+ }
+
+ mWasOnGroundLeft = onGroundLeft;
+ mWasOnGroundRight = onGroundRight;
+
+ if ( playSound )
+ {
+// F32 gain = clamp_rescale( mSpeedAccum,
+// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED,
+// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN );
+
+ const F32 STEP_VOLUME = 0.1f;
+ const LLUUID& step_sound_id = getStepSound();
+
+ LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
+
+ if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
+ && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
+ {
+ gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
+ }
+ }
+ }
+
+ mRoot.updateWorldMatrixChildren();
+
+ if (!mDebugText.size() && mText.notNull())
+ {
+ mText->markDead();
+ mText = NULL;
+ }
+ else if (mDebugText.size())
+ {
+ setDebugText(mDebugText);
+ }
+
+ //mesh vertices need to be reskinned
+ mNeedsSkin = TRUE;
+
+ return TRUE;
+}
+//-----------------------------------------------------------------------------
+// updateHeadOffset()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateHeadOffset()
+{
+ // since we only care about Z, just grab one of the eyes
+ LLVector3 midEyePt = mEyeLeftp->getWorldPosition();
+ midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot.getWorldPosition();
+ midEyePt.mV[VZ] = llmax(-mPelvisToFoot + LLViewerCamera::getInstance()->getNear(), midEyePt.mV[VZ]);
+
+ if (mDrawable.notNull())
+ {
+ midEyePt = midEyePt * ~mDrawable->getWorldRotation();
+ }
+ if (mIsSitting)
+ {
+ mHeadOffset = midEyePt;
+ }
+ else
+ {
+ F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped));
+ mHeadOffset = lerp(midEyePt, mHeadOffset, u);
+ }
+}
+//------------------------------------------------------------------------
+// setPelvisOffset
+//------------------------------------------------------------------------
+void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, F32 pelvisFixup )
+{
+ mHasPelvisOffset = hasOffset;
+ if ( mHasPelvisOffset )
+ {
+ //Store off last pelvis to foot value
+ mLastPelvisToFoot = mPelvisToFoot;
+ mPelvisOffset = offsetAmount;
+ mLastPelvisFixup = mPelvisFixup;
+ mPelvisFixup = pelvisFixup;
+ }
+}
+//------------------------------------------------------------------------
+// postPelvisSetRecalc
+//------------------------------------------------------------------------
+void LLVOAvatar::postPelvisSetRecalc( void )
+{
+ computeBodySize();
+ mRoot.touch();
+ mRoot.updateWorldMatrixChildren();
+ dirtyMesh();
+ updateHeadOffset();
+}
+//------------------------------------------------------------------------
+// pelisPoke
+//------------------------------------------------------------------------
+void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
+{
+ mHasPelvisOffset = true;
+ mLastPelvisFixup = mPelvisFixup;
+ mPelvisFixup = pelvisFixupAmount;
+}
+//------------------------------------------------------------------------
+// updateVisibility()
+//------------------------------------------------------------------------
+void LLVOAvatar::updateVisibility()
+{
+ BOOL visible = FALSE;
+
+ if (mIsDummy)
+ {
+ visible = TRUE;
+ }
+ else if (mDrawable.isNull())
+ {
+ visible = FALSE;
+ }
+ else
+ {
+ if (!mDrawable->getSpatialGroup() || mDrawable->getSpatialGroup()->isVisible())
+ {
+ visible = TRUE;
+ }
+ else
+ {
+ visible = FALSE;
+ }
+
+ if(isSelf())
+ {
+ if (!gAgentWearables.areWearablesLoaded())
+ {
+ visible = FALSE;
+ }
+ }
+ else if( !mFirstAppearanceMessageReceived )
+ {
+ visible = FALSE;
+ }
+
+ if (sDebugInvisible)
+ {
+ LLNameValue* firstname = getNVPair("FirstName");
+ if (firstname)
+ {
+ llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl;
+ }
+ else
+ {
+ llinfos << "Avatar " << this << " updating visiblity" << llendl;
+ }
+
+ if (visible)
+ {
+ llinfos << "Visible" << llendl;
+ }
+ else
+ {
+ llinfos << "Not visible" << llendl;
+ }
+
+ /*if (avatar_in_frustum)
+ {
+ llinfos << "Avatar in frustum" << llendl;
+ }
+ else
+ {
+ llinfos << "Avatar not in frustum" << llendl;
+ }*/
+
+ /*if (LLViewerCamera::getInstance()->sphereInFrustum(sel_pos_agent, 2.0f))
+ {
+ llinfos << "Sel pos visible" << llendl;
+ }
+ if (LLViewerCamera::getInstance()->sphereInFrustum(wrist_right_pos_agent, 0.2f))
+ {
+ llinfos << "Wrist pos visible" << llendl;
+ }
+ if (LLViewerCamera::getInstance()->sphereInFrustum(getPositionAgent(), getMaxScale()*2.f))
+ {
+ llinfos << "Agent visible" << llendl;
+ }*/
+ llinfos << "PA: " << getPositionAgent() << llendl;
+ /*llinfos << "SPA: " << sel_pos_agent << llendl;
+ llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject *attached_object = (*attachment_iter))
+ {
+ if(attached_object->mDrawable->isVisible())
+ {
+ llinfos << attachment->getName() << " visible" << llendl;
+ }
+ else
+ {
+ llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!visible && mVisible)
+ {
+ mMeshInvisibleTime.reset();
+ }
+
+ if (visible)
+ {
+ if (!mMeshValid)
+ {
+ restoreMeshData();
+ }
+ }
+ else
+ {
+ if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)
+ {
+ releaseMeshData();
+ }
+ // this breaks off-screen chat bubbles
+ //if (mNameText)
+ //{
+ // mNameText->markDead();
+ // mNameText = NULL;
+ // sNumVisibleChatBubbles--;
+ //}
+ }
+
+ mVisible = visible;
+}
+
+// private
+bool LLVOAvatar::shouldAlphaMask()
+{
+ const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked
+ && !LLDrawPoolAvatar::sSkipTransparent;
+
+ return should_alpha_mask;
+
+}
+
+U32 LLVOAvatar::renderSkinnedAttachments()
+{
+ /*U32 num_indices = 0;
+
+ const U32 data_mask = LLVertexBuffer::MAP_VERTEX |
+ LLVertexBuffer::MAP_NORMAL |
+ LLVertexBuffer::MAP_TEXCOORD0 |
+ LLVertexBuffer::MAP_COLOR |
+ LLVertexBuffer::MAP_WEIGHT4;
+
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object && !attached_object->isHUDAttachment())
+ {
+ const LLDrawable* drawable = attached_object->mDrawable;
+ if (drawable)
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ if (face->isState(LLFace::RIGGED))
+ {
+
+ }
+ }
+ }
+ }
+
+ return num_indices;*/
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// renderSkinned()
+//-----------------------------------------------------------------------------
+U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
+{
+ U32 num_indices = 0;
+
+ if (!mIsBuilt)
+ {
+ return num_indices;
+ }
+
+ LLFace* face = mDrawable->getFace(0);
+
+ bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
+
+ if (needs_rebuild || mDirtyMesh)
+ { //LOD changed or new mesh created, allocate new vertex buffer if needed
+ if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4)
+ {
+ updateMeshData();
+ mDirtyMesh = 0;
+ mNeedsSkin = TRUE;
+ mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
+ }
+ }
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0)
+ {
+ if (mNeedsSkin)
+ {
+ //generate animated mesh
+ mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry();
+ mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry();
+
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) )
+ {
+ mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry();
+ }
+
+ if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
+ {
+ mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry();
+ mMeshLOD[MESH_ID_HEAD]->updateJointGeometry();
+ mMeshLOD[MESH_ID_HAIR]->updateJointGeometry();
+ }
+ mNeedsSkin = FALSE;
+ mLastSkinTime = gFrameTimeSeconds;
+
+ LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer();
+ if (vb)
+ {
+ vb->setBuffer(0);
+ }
+ }
+ }
+ else
+ {
+ mNeedsSkin = FALSE;
+ }
+
+ if (sDebugInvisible)
+ {
+ LLNameValue* firstname = getNVPair("FirstName");
+ if (firstname)
+ {
+ llinfos << "Avatar " << firstname->getString() << " in render" << llendl;
+ }
+ else
+ {
+ llinfos << "Avatar " << this << " in render" << llendl;
+ }
+ if (!mIsBuilt)
+ {
+ llinfos << "Not built!" << llendl;
+ }
+ else if (!gAgent.needsRenderAvatar())
+ {
+ llinfos << "Doesn't need avatar render!" << llendl;
+ }
+ else
+ {
+ llinfos << "Rendering!" << llendl;
+ }
+ }
+
+ if (!mIsBuilt)
+ {
+ return num_indices;
+ }
+
+ if (isSelf() && !gAgent.needsRenderAvatar())
+ {
+ return num_indices;
+ }
+
+ // render collision normal
+ // *NOTE: this is disabled (there is no UI for enabling sShowFootPlane) due
+ // to DEV-14477. the code is left here to aid in tracking down the cause
+ // of the crash in the future. -brad
+ if (sShowFootPlane && mDrawable.notNull())
+ {
+ LLVector3 slaved_pos = mDrawable->getPositionAgent();
+ LLVector3 foot_plane_normal(mFootPlane.mV[VX], mFootPlane.mV[VY], mFootPlane.mV[VZ]);
+ F32 dist_from_plane = (slaved_pos * foot_plane_normal) - mFootPlane.mV[VW];
+ LLVector3 collide_point = slaved_pos;
+ collide_point.mV[VZ] -= foot_plane_normal.mV[VZ] * (dist_from_plane + COLLISION_TOLERANCE - FOOT_COLLIDE_FUDGE);
+
+ gGL.begin(LLRender::LINES);
+ {
+ F32 SQUARE_SIZE = 0.2f;
+ gGL.color4f(1.f, 0.f, 0.f, 1.f);
+
+ gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+ gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+
+ gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+ gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+
+ gGL.vertex3f(collide_point.mV[VX] + SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+ gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+
+ gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] + SQUARE_SIZE, collide_point.mV[VZ]);
+ gGL.vertex3f(collide_point.mV[VX] - SQUARE_SIZE, collide_point.mV[VY] - SQUARE_SIZE, collide_point.mV[VZ]);
+
+ gGL.vertex3f(collide_point.mV[VX], collide_point.mV[VY], collide_point.mV[VZ]);
+ gGL.vertex3f(collide_point.mV[VX] + mFootPlane.mV[VX], collide_point.mV[VY] + mFootPlane.mV[VY], collide_point.mV[VZ] + mFootPlane.mV[VZ]);
+
+ }
+ gGL.end();
+ gGL.flush();
+ }
+ //--------------------------------------------------------------------
+ // render all geometry attached to the skeleton
+ //--------------------------------------------------------------------
+ static LLStat render_stat;
+
+ LLViewerJointMesh::sRenderPass = pass;
+
+ if (pass == AVATAR_RENDER_PASS_SINGLE)
+ {
+
+ bool should_alpha_mask = shouldAlphaMask();
+ LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
+
+ if (should_alpha_mask)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+ }
+
+ BOOL first_pass = TRUE;
+ if (!LLDrawPoolAvatar::sSkipOpaque)
+ {
+ if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
+ {
+ if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
+ {
+ num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy);
+ first_pass = FALSE;
+ }
+ }
+ if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
+ {
+ num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ first_pass = FALSE;
+ }
+
+ if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
+ {
+ num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ first_pass = FALSE;
+ }
+ }
+
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+
+ if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender)
+ {
+ LLGLState blend(GL_BLEND, !mIsDummy);
+ LLGLState test(GL_ALPHA_TEST, !mIsDummy);
+ num_indices += renderTransparent(first_pass);
+ }
+ }
+
+ LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
+
+ //llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl;
+
+ //render_stat.addValue(render_timer.getElapsedTimeF32()*1000.f);
+
+ return num_indices;
+}
+
+U32 LLVOAvatar::renderTransparent(BOOL first_pass)
+{
+ U32 num_indices = 0;
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
+ num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE);
+ first_pass = FALSE;
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ }
+
+ if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
+ {
+ if (LLPipeline::sImpostorRender)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+ }
+
+ if (isTextureVisible(TEX_HEAD_BAKED))
+ {
+ num_indices += mMeshLOD[MESH_ID_EYELASH]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ first_pass = FALSE;
+ }
+ // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
+ // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
+ if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ first_pass = FALSE;
+ }
+ if (LLPipeline::sImpostorRender)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ }
+ }
+
+ return num_indices;
+}
+
+//-----------------------------------------------------------------------------
+// renderRigid()
+//-----------------------------------------------------------------------------
+U32 LLVOAvatar::renderRigid()
+{
+ U32 num_indices = 0;
+
+ if (!mIsBuilt)
+ {
+ return 0;
+ }
+
+ if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead()))
+ {
+ return 0;
+ }
+
+ if (!mIsBuilt)
+ {
+ return 0;
+ }
+
+ bool should_alpha_mask = shouldAlphaMask();
+ LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
+
+ if (should_alpha_mask)
+ {
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+ }
+
+ if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
+ {
+ num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
+ num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
+ }
+
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+
+ return num_indices;
+}
+
+U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
+{
+ if (!mImpostor.isComplete())
+ {
+ return 0;
+ }
+
+ LLVector3 pos(getRenderPosition()+mImpostorOffset);
+ LLVector3 at = (pos - LLViewerCamera::getInstance()->getOrigin());
+ at.normalize();
+ LLVector3 left = LLViewerCamera::getInstance()->getUpAxis() % at;
+ LLVector3 up = at%left;
+
+ left *= mImpostorDim.mV[0];
+ up *= mImpostorDim.mV[1];
+
+ LLGLEnable test(GL_ALPHA_TEST);
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
+
+ gGL.color4ubv(color.mV);
+ gGL.getTexUnit(diffuse_channel)->bind(&mImpostor);
+ gGL.begin(LLRender::QUADS);
+ gGL.texCoord2f(0,0);
+ gGL.vertex3fv((pos+left-up).mV);
+ gGL.texCoord2f(1,0);
+ gGL.vertex3fv((pos-left-up).mV);
+ gGL.texCoord2f(1,1);
+ gGL.vertex3fv((pos-left+up).mV);
+ gGL.texCoord2f(0,1);
+ gGL.vertex3fv((pos+left+up).mV);
+ gGL.end();
+ gGL.flush();
+
+ return 6;
+}
+
+//------------------------------------------------------------------------
+// LLVOAvatar::updateTextures()
+//------------------------------------------------------------------------
+void LLVOAvatar::updateTextures()
+{
+ BOOL render_avatar = TRUE;
+
+ if (mIsDummy)
+ {
+ return;
+ }
+
+ if( isSelf() )
+ {
+ render_avatar = TRUE;
+ }
+ else
+ {
+ if(!isVisible())
+ {
+ return ;//do not update for invisible avatar.
+ }
+
+ render_avatar = !mCulled; //visible and not culled.
+ }
+
+ std::vector<BOOL> layer_baked;
+ // GL NOT ACTIVE HERE - *TODO
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex));
+ // bind the texture so that they'll be decoded slightly
+ // inefficient, we can short-circuit this if we have to
+ if (render_avatar && !gGLManager.mIsDisabled)
+ {
+ if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded)
+ {
+ gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ));
+ }
+ }
+ }
+
+ mMaxPixelArea = 0.f;
+ mMinPixelArea = 99999999.f;
+ mHasGrey = FALSE; // debug
+ for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++)
+ {
+ LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType((ETextureIndex)texture_index);
+ U32 num_wearables = gAgentWearables.getWearableCount(wearable_type);
+ const LLTextureEntry *te = getTE(texture_index);
+ const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT);
+ LLViewerFetchedTexture *imagep = NULL;
+ for (U32 wearable_index = 0; wearable_index < num_wearables; wearable_index++)
+ {
+ imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index, wearable_index), TRUE);
+ if (imagep)
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)texture_index);
+ const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+ if (texture_dict->mIsLocalTexture)
+ {
+ addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, layer_baked[baked_index]);
+ }
+ }
+ }
+ if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar)
+ {
+ const S32 boost_level = getAvatarBakedBoostLevel();
+ imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
+ // Spam if this is a baked texture, not set to default image, without valid host info
+ if (isIndexBakedTexture((ETextureIndex)texture_index)
+ && imagep->getID() != IMG_DEFAULT_AVATAR
+ && imagep->getID() != IMG_INVISIBLE
+ && !imagep->getTargetHost().isOk())
+ {
+ LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture "
+ << imagep->getID() << " for avatar "
+ << (isSelf() ? "<myself>" : getID().asString())
+ << " on host " << getRegion()->getHost() << llendl;
+ }
+
+ addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );
+ }
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
+ {
+ setDebugText(llformat("%4.0f:%4.0f", (F32) sqrt(mMinPixelArea),(F32) sqrt(mMaxPixelArea)));
+ }
+}
+
+
+void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep,
+ F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index )
+{
+ // No local texture stats for non-self avatars
+ return;
+}
+
+const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames.
+const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames
+void LLVOAvatar::checkTextureLoading()
+{
+ static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds
+
+ BOOL pause = !isVisible() ;
+ if(!pause)
+ {
+ mInvisibleTimer.reset() ;
+ }
+ if(mLoadedCallbacksPaused == pause)
+ {
+ return ;
+ }
+
+ if(mCallbackTextureList.empty()) //when is self or no callbacks. Note: this list for self is always empty.
+ {
+ mLoadedCallbacksPaused = pause ;
+ return ; //nothing to check.
+ }
+
+ if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME)
+ {
+ return ; //have not been invisible for enough time.
+ }
+
+ for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin();
+ iter != mCallbackTextureList.end(); ++iter)
+ {
+ LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ;
+ if(tex)
+ {
+ if(pause)//pause texture fetching.
+ {
+ tex->pauseLoadedCallbacks(&mCallbackTextureList) ;
+
+ //set to terminate texture fetching after MAX_TEXTURE_UPDATE_INTERVAL frames.
+ tex->setMaxVirtualSizeResetInterval(MAX_TEXTURE_UPDATE_INTERVAL);
+ tex->resetMaxVirtualSizeResetCounter() ;
+ }
+ else//unpause
+ {
+ static const F32 START_AREA = 100.f ;
+
+ tex->unpauseLoadedCallbacks(&mCallbackTextureList) ;
+ tex->addTextureStats(START_AREA); //jump start the fetching again
+ }
+ }
+ }
+
+ if(!pause)
+ {
+ updateTextures() ; //refresh texture stats.
+ }
+ mLoadedCallbacksPaused = pause ;
+ return ;
+}
+
+const F32 SELF_ADDITIONAL_PRI = 0.75f ;
+const F32 ADDITIONAL_PRI = 0.5f;
+void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)
+{
+ //Note:
+ //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames,
+ //the texture pipeline will stop fetching this texture.
+
+ imagep->resetTextureStats();
+ imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures.
+ imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
+ imagep->resetMaxVirtualSizeResetCounter() ;
+
+ mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
+ mMinPixelArea = llmin(pixel_area, mMinPixelArea);
+ imagep->addTextureStats(pixel_area / texel_area_ratio);
+ imagep->setBoostLevel(boost_level);
+
+ if(boost_level != LLViewerTexture::BOOST_AVATAR_BAKED_SELF)
+ {
+ imagep->setAdditionalDecodePriority(ADDITIONAL_PRI) ;
+ }
+ else
+ {
+ imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
+ }
+}
+
+//virtual
+void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep, const U32 index)
+{
+ setTEImage(te, imagep);
+}
+
+//virtual
+LLViewerTexture* LLVOAvatar::getImage(const U8 te, const U32 index) const
+{
+ return getTEImage(te);
+}
+//virtual
+const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const
+{
+ return getTE(te_num);
+}
+
+//virtual
+void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te)
+{
+ setTE(index, te);
+}
+
+//-----------------------------------------------------------------------------
+// resolveHeight()
+//-----------------------------------------------------------------------------
+
+void LLVOAvatar::resolveHeightAgent(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &out_norm)
+{
+ LLVector3d in_pos_global, out_pos_global;
+
+ in_pos_global = gAgent.getPosGlobalFromAgent(in_pos_agent);
+ resolveHeightGlobal(in_pos_global, out_pos_global, out_norm);
+ out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global);
+}
+
+
+void LLVOAvatar::resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm)
+{
+ LLViewerObject *obj;
+ LLWorld::getInstance()->resolveStepHeightGlobal(this, start_pt, end_pt, out_pos, out_norm, &obj);
+}
+
+void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm)
+{
+ LLVector3d zVec(0.0f, 0.0f, 0.5f);
+ LLVector3d p0 = inPos + zVec;
+ LLVector3d p1 = inPos - zVec;
+ LLViewerObject *obj;
+ LLWorld::getInstance()->resolveStepHeightGlobal(this, p0, p1, outPos, outNorm, &obj);
+ if (!obj)
+ {
+ mStepOnLand = TRUE;
+ mStepMaterial = 0;
+ mStepObjectVelocity.setVec(0.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ mStepOnLand = FALSE;
+ mStepMaterial = obj->getMaterial();
+
+ // We want the primitive velocity, not our velocity... (which actually subtracts the
+ // step object velocity)
+ LLVector3 angularVelocity = obj->getAngularVelocity();
+ LLVector3 relativePos = gAgent.getPosAgentFromGlobal(outPos) - obj->getPositionAgent();
+
+ LLVector3 linearComponent = angularVelocity % relativePos;
+// llinfos << "Linear Component of Rotation Velocity " << linearComponent << llendl;
+ mStepObjectVelocity = obj->getVelocity() + linearComponent;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// getStepSound()
+//-----------------------------------------------------------------------------
+const LLUUID& LLVOAvatar::getStepSound() const
+{
+ if ( mStepOnLand )
+ {
+ return sStepSoundOnLand;
+ }
+
+ return sStepSounds[mStepMaterial];
+}
+
+
+//-----------------------------------------------------------------------------
+// processAnimationStateChanges()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::processAnimationStateChanges()
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) )
+ {
+ startMotion(ANIM_AGENT_WALK_ADJUST);
+ stopMotion(ANIM_AGENT_FLY_ADJUST);
+ }
+ else if (mInAir && !mIsSitting)
+ {
+ stopMotion(ANIM_AGENT_WALK_ADJUST);
+ startMotion(ANIM_AGENT_FLY_ADJUST);
+ }
+ else
+ {
+ stopMotion(ANIM_AGENT_WALK_ADJUST);
+ stopMotion(ANIM_AGENT_FLY_ADJUST);
+ }
+
+ if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
+ {
+ startMotion(ANIM_AGENT_TARGET);
+ stopMotion(ANIM_AGENT_BODY_NOISE);
+ }
+ else
+ {
+ stopMotion(ANIM_AGENT_TARGET);
+ startMotion(ANIM_AGENT_BODY_NOISE);
+ }
+
+ // clear all current animations
+ AnimIterator anim_it;
+ for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();)
+ {
+ AnimIterator found_anim = mSignaledAnimations.find(anim_it->first);
+
+ // playing, but not signaled, so stop
+ if (found_anim == mSignaledAnimations.end())
+ {
+ processSingleAnimationStateChange(anim_it->first, FALSE);
+ mPlayingAnimations.erase(anim_it++);
+ continue;
+ }
+
+ ++anim_it;
+ }
+
+ // start up all new anims
+ for (anim_it = mSignaledAnimations.begin(); anim_it != mSignaledAnimations.end();)
+ {
+ AnimIterator found_anim = mPlayingAnimations.find(anim_it->first);
+
+ // signaled but not playing, or different sequence id, start motion
+ if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second)
+ {
+ if (processSingleAnimationStateChange(anim_it->first, TRUE))
+ {
+ mPlayingAnimations[anim_it->first] = anim_it->second;
+ ++anim_it;
+ continue;
+ }
+ }
+
+ ++anim_it;
+ }
+
+ // clear source information for animations which have been stopped
+ if (isSelf())
+ {
+ AnimSourceIterator source_it = mAnimationSources.begin();
+
+ for (source_it = mAnimationSources.begin(); source_it != mAnimationSources.end();)
+ {
+ if (mSignaledAnimations.find(source_it->second) == mSignaledAnimations.end())
+ {
+ mAnimationSources.erase(source_it++);
+ }
+ else
+ {
+ ++source_it;
+ }
+ }
+ }
+
+ stop_glerror();
+}
+
+
+//-----------------------------------------------------------------------------
+// processSingleAnimationStateChange();
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start )
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ BOOL result = FALSE;
+
+ if ( start ) // start animation
+ {
+ if (anim_id == ANIM_AGENT_TYPE)
+ {
+ if (gAudiop)
+ {
+ LLVector3d char_pos_global = gAgent.getPosGlobalFromAgent(getCharacterPosition());
+ if (LLViewerParcelMgr::getInstance()->canHearSound(char_pos_global)
+ && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
+ {
+ // RN: uncomment this to play on typing sound at fixed volume once sound engine is fixed
+ // to support both spatialized and non-spatialized instances of the same sound
+ //if (isSelf())
+ //{
+ // gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
+ //}
+ //else
+ {
+ LLUUID sound_id = LLUUID(gSavedSettings.getString("UISndTyping"));
+ gAudiop->triggerSound(sound_id, getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_SFX, char_pos_global);
+ }
+ }
+ }
+ }
+ else if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED)
+ {
+ sitDown(TRUE);
+ }
+
+
+ if (startMotion(anim_id))
+ {
+ result = TRUE;
+ }
+ else
+ {
+ llwarns << "Failed to start motion!" << llendl;
+ }
+ }
+ else //stop animation
+ {
+ if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED)
+ {
+ sitDown(FALSE);
+ }
+ stopMotion(anim_id);
+ result = TRUE;
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// isAnyAnimationSignaled()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const
+{
+ for (S32 i = 0; i < num_anims; i++)
+ {
+ if(mSignaledAnimations.find(anim_array[i]) != mSignaledAnimations.end())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// resetAnimations()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetAnimations()
+{
+ LLKeyframeMotion::flushKeyframeCache();
+ flushAllMotions();
+}
+
+// Override selectively based on avatar sex and whether we're using new
+// animations.
+LLUUID LLVOAvatar::remapMotionID(const LLUUID& id)
+{
+ BOOL use_new_walk_run = gSavedSettings.getBOOL("UseNewWalkRun");
+ LLUUID result = id;
+
+ // start special case female walk for female avatars
+ if (getSex() == SEX_FEMALE)
+ {
+ if (id == ANIM_AGENT_WALK)
+ {
+ if (use_new_walk_run)
+ result = ANIM_AGENT_FEMALE_WALK_NEW;
+ else
+ result = ANIM_AGENT_FEMALE_WALK;
+ }
+ else if (id == ANIM_AGENT_RUN)
+ {
+ // There is no old female run animation, so only override
+ // in one case.
+ if (use_new_walk_run)
+ result = ANIM_AGENT_FEMALE_RUN_NEW;
+ }
+ else if (id == ANIM_AGENT_SIT)
+ {
+ result = ANIM_AGENT_SIT_FEMALE;
+ }
+ }
+ else
+ {
+ // Male avatar.
+ if (id == ANIM_AGENT_WALK)
+ {
+ if (use_new_walk_run)
+ result = ANIM_AGENT_WALK_NEW;
+ }
+ else if (id == ANIM_AGENT_RUN)
+ {
+ if (use_new_walk_run)
+ result = ANIM_AGENT_RUN_NEW;
+ }
+
+ }
+
+ return result;
+
+}
+
+//-----------------------------------------------------------------------------
+// startMotion()
+// id is the asset if of the animation to start
+// time_offset is the offset into the animation at which to start playing
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
+
+ LLUUID remap_id = remapMotionID(id);
+
+ if (remap_id != id)
+ {
+ lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
+ }
+
+ if (isSelf() && remap_id == ANIM_AGENT_AWAY)
+ {
+ gAgent.setAFK();
+ }
+
+ return LLCharacter::startMotion(remap_id, time_offset);
+}
+
+//-----------------------------------------------------------------------------
+// stopMotion()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate)
+{
+ lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl;
+
+ LLUUID remap_id = remapMotionID(id);
+
+ if (remap_id != id)
+ {
+ lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl;
+ }
+
+ if (isSelf())
+ {
+ gAgent.onAnimStop(remap_id);
+ }
+
+ return LLCharacter::stopMotion(remap_id, stop_immediate);
+}
+
+//-----------------------------------------------------------------------------
+// stopMotionFromSource()
+//-----------------------------------------------------------------------------
+// virtual
+void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id)
+{
+}
+
+//-----------------------------------------------------------------------------
+// getVolumePos()
+//-----------------------------------------------------------------------------
+LLVector3 LLVOAvatar::getVolumePos(S32 joint_index, LLVector3& volume_offset)
+{
+ if (joint_index > mNumCollisionVolumes)
+ {
+ return LLVector3::zero;
+ }
+
+ return mCollisionVolumes[joint_index].getVolumePos(volume_offset);
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+LLJoint* LLVOAvatar::findCollisionVolume(U32 volume_id)
+{
+ if ((S32)volume_id > mNumCollisionVolumes)
+ {
+ return NULL;
+ }
+
+ return &mCollisionVolumes[volume_id];
+}
+
+//-----------------------------------------------------------------------------
+// findCollisionVolume()
+//-----------------------------------------------------------------------------
+S32 LLVOAvatar::getCollisionVolumeID(std::string &name)
+{
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ if (mCollisionVolumes[i].getName() == name)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// addDebugText()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::addDebugText(const std::string& text)
+{
+ mDebugText.append(1, '\n');
+ mDebugText.append(text);
+}
+
+//-----------------------------------------------------------------------------
+// getID()
+//-----------------------------------------------------------------------------
+const LLUUID& LLVOAvatar::getID()
+{
+ return mID;
+}
+
+//-----------------------------------------------------------------------------
+// getJoint()
+//-----------------------------------------------------------------------------
+// RN: avatar joints are multi-rooted to include screen-based attachments
+LLJoint *LLVOAvatar::getJoint( const std::string &name )
+{
+ LLJoint* jointp = mRoot.findJoint(name);
+ return jointp;
+}
+
+//-----------------------------------------------------------------------------
+// resetJointPositions
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetJointPositions( void )
+{
+ for(S32 i = 0; i < (S32)mNumJoints; ++i)
+ {
+ mSkeleton[i].restoreOldXform();
+ mSkeleton[i].setId( LLUUID::null );
+ }
+ mHasPelvisOffset = false;
+ mPelvisFixup = mLastPelvisFixup;
+}
+//-----------------------------------------------------------------------------
+// resetSpecificJointPosition
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetSpecificJointPosition( const std::string& name )
+{
+ LLJoint* pJoint = mRoot.findJoint( name );
+
+ if ( pJoint && pJoint->doesJointNeedToBeReset() )
+ {
+ pJoint->restoreOldXform();
+ pJoint->setId( LLUUID::null );
+ //If we're reseting the pelvis position make sure not to apply offset
+ if ( name == "mPelvis" )
+ {
+ mHasPelvisOffset = false;
+ }
+ }
+ else
+ {
+ llinfos<<"Did not find "<< name.c_str()<<llendl;
+ }
+}
+//-----------------------------------------------------------------------------
+// resetJointPositionsToDefault
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetJointPositionsToDefault( void )
+{
+ const LLVector3& avPos = getCharacterPosition();
+
+ //Reposition the pelvis
+ LLJoint* pPelvis = mRoot.findJoint("mPelvis");
+ if ( pPelvis )
+ {
+ pPelvis->setPosition( avPos + pPelvis->getPosition() );
+ }
+ else
+ {
+ llwarns<<"Can't get pelvis joint."<<llendl;
+ return;
+ }
+
+ //Subsequent joints are relative to pelvis
+ for( S32 i = 0; i < (S32)mNumJoints; ++i )
+ {
+ LLJoint* pJoint = (LLJoint*)&mSkeleton[i];
+ if ( pJoint->doesJointNeedToBeReset() )
+ {
+
+ pJoint->setId( LLUUID::null );
+ //restore joints to default positions, however skip over the pelvis
+ if ( pJoint && pPelvis != pJoint )
+ {
+ pJoint->restoreOldXform();
+ }
+ }
+ }
+ //make sure we don't apply the joint offset
+ mHasPelvisOffset = false;
+ mPelvisFixup = mLastPelvisFixup;
+ postPelvisSetRecalc();
+}
+//-----------------------------------------------------------------------------
+// getCharacterPosition()
+//-----------------------------------------------------------------------------
+LLVector3 LLVOAvatar::getCharacterPosition()
+{
+ if (mDrawable.notNull())
+ {
+ return mDrawable->getPositionAgent();
+ }
+ else
+ {
+ return getPositionAgent();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getCharacterRotation()
+//-----------------------------------------------------------------------------
+LLQuaternion LLVOAvatar::getCharacterRotation()
+{
+ return getRotation();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getCharacterVelocity()
+//-----------------------------------------------------------------------------
+LLVector3 LLVOAvatar::getCharacterVelocity()
+{
+ return getVelocity() - mStepObjectVelocity;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getCharacterAngularVelocity()
+//-----------------------------------------------------------------------------
+LLVector3 LLVOAvatar::getCharacterAngularVelocity()
+{
+ return getAngularVelocity();
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getGround()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_agent, LLVector3 &outNorm)
+{
+ LLVector3d z_vec(0.0f, 0.0f, 1.0f);
+ LLVector3d p0_global, p1_global;
+
+ if (mIsDummy)
+ {
+ outNorm.setVec(z_vec);
+ out_pos_agent = in_pos_agent;
+ return;
+ }
+
+ p0_global = gAgent.getPosGlobalFromAgent(in_pos_agent) + z_vec;
+ p1_global = gAgent.getPosGlobalFromAgent(in_pos_agent) - z_vec;
+ LLViewerObject *obj;
+ LLVector3d out_pos_global;
+ LLWorld::getInstance()->resolveStepHeightGlobal(this, p0_global, p1_global, out_pos_global, outNorm, &obj);
+ out_pos_agent = gAgent.getPosAgentFromGlobal(out_pos_global);
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getTimeDilation()
+//-----------------------------------------------------------------------------
+F32 LLVOAvatar::getTimeDilation()
+{
+ return mTimeDilation;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getPixelArea()
+//-----------------------------------------------------------------------------
+F32 LLVOAvatar::getPixelArea() const
+{
+ if (mIsDummy)
+ {
+ return 100000.f;
+ }
+ return mPixelArea;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getHeadMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLVOAvatar::getHeadMesh()
+{
+ return mMeshLOD[MESH_ID_HEAD]->mMeshParts[0]->getMesh();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getUpperBodyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh* LLVOAvatar::getUpperBodyMesh()
+{
+ return mMeshLOD[MESH_ID_UPPER_BODY]->mMeshParts[0]->getMesh();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLVOAvatar::getPosGlobalFromAgent()
+//-----------------------------------------------------------------------------
+LLVector3d LLVOAvatar::getPosGlobalFromAgent(const LLVector3 &position)
+{
+ return gAgent.getPosGlobalFromAgent(position);
+}
+
+//-----------------------------------------------------------------------------
+// getPosAgentFromGlobal()
+//-----------------------------------------------------------------------------
+LLVector3 LLVOAvatar::getPosAgentFromGlobal(const LLVector3d &position)
+{
+ return gAgent.getPosAgentFromGlobal(position);
+}
+
+//-----------------------------------------------------------------------------
+// allocateCharacterJoints()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::allocateCharacterJoints( U32 num )
+{
+ deleteAndClearArray(mSkeleton);
+ mNumJoints = 0;
+
+ mSkeleton = new LLViewerJoint[num];
+
+ for(S32 joint_num = 0; joint_num < (S32)num; joint_num++)
+ {
+ mSkeleton[joint_num].setJointNum(joint_num);
+ }
+
+ if (!mSkeleton)
+ {
+ return FALSE;
+ }
+
+ mNumJoints = num;
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// allocateCollisionVolumes()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::allocateCollisionVolumes( U32 num )
+{
+ deleteAndClearArray(mCollisionVolumes);
+ mNumCollisionVolumes = 0;
+
+ mCollisionVolumes = new LLViewerJointCollisionVolume[num];
+ if (!mCollisionVolumes)
+ {
+ return FALSE;
+ }
+
+ mNumCollisionVolumes = num;
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// getCharacterJoint()
+//-----------------------------------------------------------------------------
+LLJoint *LLVOAvatar::getCharacterJoint( U32 num )
+{
+ if ((S32)num >= mNumJoints
+ || (S32)num < 0)
+ {
+ return NULL;
+ }
+ return (LLJoint*)&mSkeleton[num];
+}
+
+//-----------------------------------------------------------------------------
+// requestStopMotion()
+//-----------------------------------------------------------------------------
+// virtual
+void LLVOAvatar::requestStopMotion( LLMotion* motion )
+{
+ // Only agent avatars should handle the stop motion notifications.
+}
+
+//-----------------------------------------------------------------------------
+// loadAvatar()
+//-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar");
+
+BOOL LLVOAvatar::loadAvatar()
+{
+// LLFastTimer t(FTM_LOAD_AVATAR);
+
+ // avatar_skeleton.xml
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ llwarns << "avatar file: buildSkeleton() failed" << llendl;
+ return FALSE;
+ }
+
+ // avatar_lad.xml : <skeleton>
+ if( !loadSkeletonNode() )
+ {
+ llwarns << "avatar file: loadNodeSkeleton() failed" << llendl;
+ return FALSE;
+ }
+
+ // avatar_lad.xml : <mesh>
+ if( !loadMeshNodes() )
+ {
+ llwarns << "avatar file: loadNodeMesh() failed" << llendl;
+ return FALSE;
+ }
+
+ // avatar_lad.xml : <global_color>
+ if( sAvatarXmlInfo->mTexSkinColorInfo )
+ {
+ mTexSkinColor = new LLTexGlobalColor( this );
+ if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
+ {
+ llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl;
+ return FALSE;
+ }
+ }
+ else
+ {
+ llwarns << "<global_color> name=\"skin_color\" not found" << llendl;
+ return FALSE;
+ }
+ if( sAvatarXmlInfo->mTexHairColorInfo )
+ {
+ mTexHairColor = new LLTexGlobalColor( this );
+ if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
+ {
+ llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl;
+ return FALSE;
+ }
+ }
+ else
+ {
+ llwarns << "<global_color> name=\"hair_color\" not found" << llendl;
+ return FALSE;
+ }
+ if( sAvatarXmlInfo->mTexEyeColorInfo )
+ {
+ mTexEyeColor = new LLTexGlobalColor( this );
+ if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
+ {
+ llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl;
+ return FALSE;
+ }
+ }
+ else
+ {
+ llwarns << "<global_color> name=\"eye_color\" not found" << llendl;
+ return FALSE;
+ }
+
+ // avatar_lad.xml : <layer_set>
+ if (sAvatarXmlInfo->mLayerInfoList.empty())
+ {
+ llwarns << "avatar file: missing <layer_set> node" << llendl;
+ return FALSE;
+ }
+
+ if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
+ {
+ llwarns << "avatar file: missing <morph_masks> node" << llendl;
+ return FALSE;
+ }
+
+ // avatar_lad.xml : <morph_masks>
+ for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin();
+ iter != sAvatarXmlInfo->mMorphMaskInfoList.end();
+ ++iter)
+ {
+ LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter;
+
+ EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion);
+ if (baked != BAKED_NUM_INDICES)
+ {
+ LLPolyMorphTarget *morph_param;
+ const std::string *name = &info->mName;
+ morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str()));
+ if (morph_param)
+ {
+ BOOL invert = info->mInvert;
+ addMaskedMorph(baked, morph_param, invert, info->mLayer);
+ }
+ }
+
+ }
+
+ loadLayersets();
+
+ // avatar_lad.xml : <driver_parameters>
+ for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin();
+ iter != sAvatarXmlInfo->mDriverInfoList.end();
+ ++iter)
+ {
+ LLDriverParamInfo *info = *iter;
+ LLDriverParam* driver_param = new LLDriverParam( this );
+ if (driver_param->setInfo(info))
+ {
+ addVisualParam( driver_param );
+ LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam;
+ if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false))
+ {
+ llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl;
+ continue;
+ }
+ }
+ else
+ {
+ delete driver_param;
+ llwarns << "avatar file: driver_param->parseData() failed" << llendl;
+ return FALSE;
+ }
+ }
+
+ // Uncomment to enable avatar_lad.xml debugging.
+ std::ofstream file;
+ file.open("avatar_lad.log");
+ for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam();
+ param;
+ param = (LLViewerVisualParam*) getNextVisualParam() )
+ {
+ param->getInfo()->toStream(file);
+ file << std::endl;
+ }
+
+ file.close();
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// loadSkeletonNode(): loads <skeleton> node from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::loadSkeletonNode ()
+{
+ mRoot.addChild( &mSkeleton[0] );
+
+ for (std::vector<LLViewerJoint *>::iterator iter = mMeshLOD.begin();
+ iter != mMeshLOD.end();
+ ++iter)
+ {
+ LLViewerJoint *joint = (LLViewerJoint *) *iter;
+ joint->mUpdateXform = FALSE;
+ joint->setMeshesToChildren();
+ }
+
+ mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
+ mRoot.addChild(mMeshLOD[MESH_ID_EYELASH]);
+ mRoot.addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
+ mRoot.addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
+ mRoot.addChild(mMeshLOD[MESH_ID_SKIRT]);
+ mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
+
+ LLViewerJoint *skull = (LLViewerJoint*)mRoot.findJoint("mSkull");
+ if (skull)
+ {
+ skull->addChild(mMeshLOD[MESH_ID_HAIR] );
+ }
+
+ LLViewerJoint *eyeL = (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
+ if (eyeL)
+ {
+ eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
+ }
+
+ LLViewerJoint *eyeR = (LLViewerJoint*)mRoot.findJoint("mEyeRight");
+ if (eyeR)
+ {
+ eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
+ }
+
+ // SKELETAL DISTORTIONS
+ {
+ LLVOAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter;
+ for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin();
+ iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end();
+ ++iter)
+ {
+ LLPolySkeletalDistortionInfo *info = *iter;
+ LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
+ if (!param->setInfo(info))
+ {
+ delete param;
+ return FALSE;
+ }
+ else
+ {
+ addVisualParam(param);
+ }
+ }
+ }
+
+ // ATTACHMENTS
+ {
+ LLVOAvatarXmlInfo::attachment_info_list_t::iterator iter;
+ for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
+ iter != sAvatarXmlInfo->mAttachmentInfoList.end();
+ ++iter)
+ {
+ LLVOAvatarXmlInfo::LLVOAvatarAttachmentInfo *info = *iter;
+ if (!isSelf() && info->mJointName == "mScreen")
+ { //don't process screen joint for other avatars
+ continue;
+ }
+
+ LLViewerJointAttachment* attachment = new LLViewerJointAttachment();
+
+ attachment->setName(info->mName);
+ LLJoint *parentJoint = getJoint(info->mJointName);
+ if (!parentJoint)
+ {
+ llwarns << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << llendl;
+ delete attachment;
+ continue;
+ }
+
+ if (info->mHasPosition)
+ {
+ attachment->setOriginalPosition(info->mPosition);
+ }
+
+ if (info->mHasRotation)
+ {
+ LLQuaternion rotation;
+ rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
+ info->mRotationEuler.mV[VY] * DEG_TO_RAD,
+ info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
+ attachment->setRotation(rotation);
+ }
+
+ int group = info->mGroup;
+ if (group >= 0)
+ {
+ if (group < 0 || group >= 9)
+ {
+ llwarns << "Invalid group number (" << group << ") for attachment point " << info->mName << llendl;
+ }
+ else
+ {
+ attachment->setGroup(group);
+ }
+ }
+
+ S32 attachmentID = info->mAttachmentID;
+ if (attachmentID < 1 || attachmentID > 255)
+ {
+ llwarns << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << llendl;
+ delete attachment;
+ continue;
+ }
+ if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end())
+ {
+ llwarns << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << llendl;
+ delete attachment;
+ continue;
+ }
+
+ attachment->setPieSlice(info->mPieMenuSlice);
+ attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
+ attachment->setIsHUDAttachment(info->mIsHUDAttachment);
+
+ mAttachmentPoints[attachmentID] = attachment;
+
+ // now add attachment joint
+ parentJoint->addChild(attachment);
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// loadMeshNodes(): loads <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::loadMeshNodes()
+{
+ for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin();
+ meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end();
+ ++meshinfo_iter)
+ {
+ const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter;
+ const std::string &type = info->mType;
+ S32 lod = info->mLOD;
+
+ LLViewerJointMesh* mesh = NULL;
+ U8 mesh_id = 0;
+ BOOL found_mesh_id = FALSE;
+
+ /* if (type == "hairMesh")
+ switch(lod)
+ case 0:
+ mesh = &mHairMesh0; */
+ for (LLVOAvatarDictionary::Meshes::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin();
+ mesh_iter != LLVOAvatarDictionary::getInstance()->getMeshes().end();
+ ++mesh_iter)
+ {
+ const EMeshIndex mesh_index = mesh_iter->first;
+ const LLVOAvatarDictionary::MeshEntry *mesh_dict = mesh_iter->second;
+ if (type.compare(mesh_dict->mName) == 0)
+ {
+ mesh_id = mesh_index;
+ found_mesh_id = TRUE;
+ break;
+ }
+ }
+
+ if (found_mesh_id)
+ {
+ if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
+ {
+ mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
+ }
+ else
+ {
+ llwarns << "Avatar file: <mesh> has invalid lod setting " << lod << llendl;
+ return FALSE;
+ }
+ }
+ else
+ {
+ llwarns << "Ignoring unrecognized mesh type: " << type << llendl;
+ return FALSE;
+ }
+
+ // llinfos << "Parsing mesh data for " << type << "..." << llendl;
+
+ // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
+ // Do not touch!!!
+ mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f );
+
+ LLPolyMesh *poly_mesh = NULL;
+
+ if (!info->mReferenceMeshName.empty())
+ {
+ polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName);
+ if (polymesh_iter != mMeshes.end())
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
+ poly_mesh->setAvatar(this);
+ }
+ else
+ {
+ // This should never happen
+ LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
+ }
+ }
+ else
+ {
+ poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
+ poly_mesh->setAvatar(this);
+ }
+
+ if( !poly_mesh )
+ {
+ llwarns << "Failed to load mesh of type " << type << llendl;
+ return FALSE;
+ }
+
+ // Multimap insert
+ mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
+
+ mesh->setMesh( poly_mesh );
+ mesh->setLOD( info->mMinPixelArea );
+
+ for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin();
+ xmlinfo_iter != info->mPolyMorphTargetInfoList.end();
+ ++xmlinfo_iter)
+ {
+ const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter);
+ LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
+ if (!param->setInfo(info_pair->first))
+ {
+ delete param;
+ return FALSE;
+ }
+ else
+ {
+ if (info_pair->second)
+ {
+ addSharedVisualParam(param);
+ }
+ else
+ {
+ addVisualParam(param);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// loadLayerSets()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::loadLayersets()
+{
+ BOOL success = TRUE;
+ for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin();
+ layerset_iter != sAvatarXmlInfo->mLayerInfoList.end();
+ ++layerset_iter)
+ {
+ // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+ LLTexLayerSetInfo *layerset_info = *layerset_iter;
+ layerset_info->createVisualParams(this);
+ }
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+// updateVisualParams()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateVisualParams()
+{
+ setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE );
+
+ LLCharacter::updateVisualParams();
+
+ if (mLastSkeletonSerialNum != mSkeletonSerialNum)
+ {
+ computeBodySize();
+ mLastSkeletonSerialNum = mSkeletonSerialNum;
+ mRoot.updateWorldMatrixChildren();
+ }
+
+ dirtyMesh();
+ updateHeadOffset();
+}
+
+//-----------------------------------------------------------------------------
+// isActive()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::isActive() const
+{
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// setPixelAreaAndAngle()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
+{
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+ LLVector4a center;
+ center.setAdd(ext[1], ext[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
+
+ F32 range = mDrawable->mDistanceWRTCamera;
+
+ if (range < 0.001f) // range == zero
+ {
+ mAppAngle = 180.f;
+ }
+ else
+ {
+ F32 radius = size.getLength3().getF32();
+ mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG;
+ }
+
+ // We always want to look good to ourselves
+ if( isSelf() )
+ {
+ mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// updateJointLODs()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::updateJointLODs()
+{
+ const F32 MAX_PIXEL_AREA = 100000000.f;
+ F32 lod_factor = (sLODFactor * AVATAR_LOD_TWEAK_RANGE + (1.f - AVATAR_LOD_TWEAK_RANGE));
+ F32 avatar_num_min_factor = clamp_rescale(sLODFactor, 0.f, 1.f, 0.25f, 0.6f);
+ F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor);
+ F32 area_scale = 0.16f;
+
+ {
+ if (isSelf())
+ {
+ if(gAgentCamera.cameraCustomizeAvatar() || gAgentCamera.cameraMouselook())
+ {
+ mAdjustedPixelArea = MAX_PIXEL_AREA;
+ }
+ else
+ {
+ mAdjustedPixelArea = mPixelArea*area_scale;
+ }
+ }
+ else if (mIsDummy)
+ {
+ mAdjustedPixelArea = MAX_PIXEL_AREA;
+ }
+ else
+ {
+ // reported avatar pixel area is dependent on avatar render load, based on number of visible avatars
+ mAdjustedPixelArea = (F32)mPixelArea * area_scale * lod_factor * lod_factor * avatar_num_factor * avatar_num_factor;
+ }
+
+ // now select meshes to render based on adjusted pixel area
+ BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE);
+ if (res)
+ {
+ sNumLODChangesThisFrame++;
+ dirtyMesh(2);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// createDrawable()
+//-----------------------------------------------------------------------------
+LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+ mDrawable->setLit(FALSE);
+
+ LLDrawPoolAvatar *poolp = (LLDrawPoolAvatar*) gPipeline.getPool(LLDrawPool::POOL_AVATAR);
+
+ // Only a single face (one per avatar)
+ //this face will be splitted into several if its vertex buffer is too long.
+ mDrawable->setState(LLDrawable::ACTIVE);
+ mDrawable->addFace(poolp, NULL);
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR);
+
+ mNumInitFaces = mDrawable->getNumFaces() ;
+
+ dirtyMesh(2);
+ return mDrawable;
+}
+
+
+void LLVOAvatar::updateGL()
+{
+ if (mMeshTexturesDirty)
+ {
+ updateMeshTextures();
+ mMeshTexturesDirty = FALSE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// updateGeometry()
+//-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar");
+BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
+{
+ LLFastTimer ftm(FTM_UPDATE_AVATAR);
+ if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
+ {
+ return TRUE;
+ }
+
+ if (!mMeshValid)
+ {
+ return TRUE;
+ }
+
+ if (!drawable)
+ {
+ llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl;
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// updateSexDependentLayerSets()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake )
+{
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
+}
+
+//-----------------------------------------------------------------------------
+// dirtyMesh()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::dirtyMesh()
+{
+ dirtyMesh(1);
+}
+void LLVOAvatar::dirtyMesh(S32 priority)
+{
+ mDirtyMesh = llmax(mDirtyMesh, priority);
+}
+//-----------------------------------------------------------------------------
+// hideSkirt()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::hideSkirt()
+{
+ mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE);
+}
+
+BOOL LLVOAvatar::setParent(LLViewerObject* parent)
+{
+ BOOL ret ;
+ if (parent == NULL)
+ {
+ getOffObject();
+ ret = LLViewerObject::setParent(parent);
+ if (isSelf())
+ {
+ gAgentCamera.resetCamera();
+ }
+ }
+ else
+ {
+ ret = LLViewerObject::setParent(parent);
+ if(ret)
+ {
+ sitOnObject(parent);
+ }
+ }
+ return ret ;
+}
+
+void LLVOAvatar::addChild(LLViewerObject *childp)
+{
+ childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
+ LLViewerObject::addChild(childp);
+ if (childp->mDrawable)
+ {
+ attachObject(childp);
+ }
+ else
+ {
+ mPendingAttachment.push_back(childp);
+ }
+}
+
+void LLVOAvatar::removeChild(LLViewerObject *childp)
+{
+ LLViewerObject::removeChild(childp);
+ if (!detachObject(childp))
+ {
+ llwarns << "Calling detach on non-attached object " << llendl;
+ }
+}
+
+LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
+{
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
+
+ // This should never happen unless the server didn't process the attachment point
+ // correctly, but putting this check in here to be safe.
+ if (attachmentID & ATTACHMENT_ADD)
+ {
+ llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;
+ attachmentID &= ~ATTACHMENT_ADD;
+ }
+
+ LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
+
+ if (!attachment)
+ {
+ llwarns << "Object attachment point invalid: " << attachmentID << llendl;
+ attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest)
+ }
+
+ return attachment;
+}
+
+//-----------------------------------------------------------------------------
+// attachObject()
+//-----------------------------------------------------------------------------
+const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object)
+{
+ LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object);
+
+ if (!attachment || !attachment->addObject(viewer_object))
+ {
+ return 0;
+ }
+
+ if (viewer_object->isSelected())
+ {
+ LLSelectMgr::getInstance()->updateSelectionCenter();
+ LLSelectMgr::getInstance()->updatePointAt();
+ }
+
+ return attachment;
+}
+
+//-----------------------------------------------------------------------------
+// attachObject()
+//-----------------------------------------------------------------------------
+U32 LLVOAvatar::getNumAttachments() const
+{
+ U32 num_attachments = 0;
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ const LLViewerJointAttachment *attachment_pt = (*iter).second;
+ num_attachments += attachment_pt->getNumObjects();
+ }
+ return num_attachments;
+}
+
+//-----------------------------------------------------------------------------
+// canAttachMoreObjects()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::canAttachMoreObjects() const
+{
+ return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
+}
+
+//-----------------------------------------------------------------------------
+// canAttachMoreObjects()
+// Returns true if we can attach <n> more objects.
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
+{
+ return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
+}
+
+//-----------------------------------------------------------------------------
+// lazyAttach()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::lazyAttach()
+{
+ std::vector<LLPointer<LLViewerObject> > still_pending;
+
+ for (U32 i = 0; i < mPendingAttachment.size(); i++)
+ {
+ if (mPendingAttachment[i]->mDrawable)
+ {
+ attachObject(mPendingAttachment[i]);
+ }
+ else
+ {
+ still_pending.push_back(mPendingAttachment[i]);
+ }
+ }
+
+ mPendingAttachment = still_pending;
+}
+
+void LLVOAvatar::resetHUDAttachments()
+{
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (attachment->getIsHUDAttachment())
+ {
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object && attached_object->mDrawable.notNull())
+ {
+ gPipeline.markMoved(attached_object->mDrawable);
+ }
+ }
+ }
+ }
+}
+
+void LLVOAvatar::rebuildRiggedAttachments( void )
+{
+ for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
+ {
+ LLViewerJointAttachment* pAttachment = iter->second;
+ LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end();
+
+ for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin();
+ attachmentIter != attachmentIterEnd; ++attachmentIter)
+ {
+ const LLViewerObject* pAttachedObject = *attachmentIter;
+ if ( pAttachment && pAttachedObject->mDrawable.notNull() )
+ {
+ gPipeline.markRebuild(pAttachedObject->mDrawable);
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// cleanupAttachedMesh()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
+{
+ //If a VO has a skin that we'll reset the joint positions to their default
+ if ( pVO && pVO->mDrawable )
+ {
+ LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
+ if ( pVObj )
+ {
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID() );
+ if ( pSkinData )
+ {
+ const int jointCnt = pSkinData->mJointNames.size();
+ bool fullRig = ( jointCnt>=20 ) ? true : false;
+ if ( fullRig )
+ {
+ const int bindCnt = pSkinData->mAlternateBindMatrix.size();
+ if ( bindCnt > 0 )
+ {
+ LLVOAvatar::resetJointPositionsToDefault();
+ }
+ }
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+// detachObject()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
+{
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+
+ if (attachment->isObjectAttached(viewer_object))
+ {
+ cleanupAttachedMesh( viewer_object );
+ attachment->removeObject(viewer_object);
+ lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;
+ return TRUE;
+ }
+ }
+
+ std::vector<LLPointer<LLViewerObject> >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object);
+ if (iter != mPendingAttachment.end())
+ {
+ mPendingAttachment.erase(iter);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// sitDown()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::sitDown(BOOL bSitting)
+{
+ mIsSitting = bSitting;
+ if (isSelf())
+ {
+ // Update Movement Controls according to own Sitting mode
+ LLFloaterMove::setSittingMode(bSitting);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// sitOnObject()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
+{
+ if (isSelf())
+ {
+ // Might be first sit
+ //LLFirstUse::useSit();
+
+ gAgent.setFlying(FALSE);
+ gAgentCamera.setThirdPersonHeadOffset(LLVector3::zero);
+ //interpolate to new camera position
+ gAgentCamera.startCameraAnimation();
+ // make sure we are not trying to autopilot
+ gAgent.stopAutoPilot();
+ gAgentCamera.setupSitCamera();
+ if (gAgentCamera.getForceMouselook())
+ {
+ gAgentCamera.changeCameraToMouselook();
+ }
+ }
+
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+ LLQuaternion inv_obj_rot = ~sit_object->getRenderRotation();
+ LLVector3 obj_pos = sit_object->getRenderPosition();
+
+ LLVector3 rel_pos = getRenderPosition() - obj_pos;
+ rel_pos.rotVec(inv_obj_rot);
+
+ mDrawable->mXform.setPosition(rel_pos);
+ mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot);
+
+ gPipeline.markMoved(mDrawable, TRUE);
+ // Notice that removing sitDown() from here causes avatars sitting on
+ // objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
+ sitDown(TRUE);
+ mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
+ mRoot.setPosition(getPosition());
+ mRoot.updateWorldMatrixChildren();
+
+ stopMotion(ANIM_AGENT_BODY_NOISE);
+
+}
+
+//-----------------------------------------------------------------------------
+// getOffObject()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::getOffObject()
+{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ LLViewerObject* sit_object = (LLViewerObject*)getParent();
+
+ if (sit_object)
+ {
+ stopMotionFromSource(sit_object->getID());
+ LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
+
+ LLViewerObject::const_child_list_t& child_list = sit_object->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* child_objectp = *iter;
+
+ stopMotionFromSource(child_objectp->getID());
+ LLFollowCamMgr::setCameraActive(child_objectp->getID(), FALSE);
+ }
+ }
+
+ // assumes that transform will not be updated with drawable still having a parent
+ LLVector3 cur_position_world = mDrawable->getWorldPosition();
+ LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
+
+ // set *local* position based on last *world* position, since we're unparenting the avatar
+ mDrawable->mXform.setPosition(cur_position_world);
+ mDrawable->mXform.setRotation(cur_rotation_world);
+
+ gPipeline.markMoved(mDrawable, TRUE);
+
+ sitDown(FALSE);
+
+ mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject
+ mRoot.setPosition(cur_position_world);
+ mRoot.setRotation(cur_rotation_world);
+ mRoot.getXform()->update();
+
+ startMotion(ANIM_AGENT_BODY_NOISE);
+
+ if (isSelf())
+ {
+ LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion();
+ LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT;
+ av_rot = av_rot * obj_rot;
+ LLVector3 at_axis = LLVector3::x_axis;
+ at_axis = at_axis * av_rot;
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ gAgent.resetAxes(at_axis);
+
+ //reset orientation
+// mRoot.setRotation(avWorldRot);
+ gAgentCamera.setThirdPersonHeadOffset(LLVector3(0.f, 0.f, 1.f));
+
+ gAgentCamera.setSitCamera(LLUUID::null);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// findAvatarFromAttachment()
+//-----------------------------------------------------------------------------
+// static
+LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj )
+{
+ if( obj->isAttachment() )
+ {
+ do
+ {
+ obj = (LLViewerObject*) obj->getParent();
+ }
+ while( obj && !obj->isAvatar() );
+
+ if( obj && !obj->isDead() )
+ {
+ return (LLVOAvatar*)obj;
+ }
+ }
+ return NULL;
+}
+
+// warning: order(N) not order(1)
+S32 LLVOAvatar::getAttachmentCount()
+{
+ S32 count = mAttachmentPoints.size();
+ return count;
+}
+
+LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const
+{
+ if (color_name=="skin_color" && mTexSkinColor)
+ {
+ return mTexSkinColor->getColor();
+ }
+ else if(color_name=="hair_color" && mTexHairColor)
+ {
+ return mTexHairColor->getColor();
+ }
+ if(color_name=="eye_color" && mTexEyeColor)
+ {
+ return mTexEyeColor->getColor();
+ }
+ else
+ {
+// return LLColor4( .5f, .5f, .5f, .5f );
+ return LLColor4( 0.f, 1.f, 1.f, 1.f ); // good debugging color
+ }
+}
+
+// virtual
+void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )
+{
+}
+
+void LLVOAvatar::invalidateAll()
+{
+}
+
+void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake )
+{
+ if (global_color == mTexSkinColor)
+ {
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake );
+ }
+ else if (global_color == mTexHairColor)
+ {
+ invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake );
+ invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake );
+
+ // ! BACKWARDS COMPATIBILITY !
+ // Fix for dealing with avatars from viewers that don't bake hair.
+ if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex))
+ {
+ LLColor4 color = mTexHairColor->getColor();
+ for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
+ {
+ mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] );
+ }
+ }
+ }
+ else if (global_color == mTexEyeColor)
+ {
+// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl;
+ invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake );
+ }
+ updateMeshTextures();
+}
+
+BOOL LLVOAvatar::isVisible() const
+{
+ return mDrawable.notNull()
+ && (mDrawable->isVisible() || mIsDummy);
+}
+
+// Determine if we have enough avatar data to render
+BOOL LLVOAvatar::getIsCloud()
+{
+ // Do we have a shape?
+ if (visualParamWeightsAreDefault())
+ {
+ return TRUE;
+ }
+
+ if (!isTextureDefined(TEX_LOWER_BAKED) ||
+ !isTextureDefined(TEX_UPPER_BAKED) ||
+ !isTextureDefined(TEX_HEAD_BAKED))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// call periodically to keep isFullyLoaded up to date.
+// returns true if the value has changed.
+BOOL LLVOAvatar::updateIsFullyLoaded()
+{
+ const BOOL loading = getIsCloud();
+ updateRuthTimer(loading);
+ return processFullyLoadedChange(loading);
+}
+
+void LLVOAvatar::updateRuthTimer(bool loading)
+{
+ if (isSelf() || !loading)
+ {
+ return;
+ }
+
+ if (mPreviousFullyLoaded)
+ {
+ mRuthTimer.reset();
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezCloudNotification",args);
+ }
+ mRuthDebugTimer.reset();
+ }
+
+ const F32 LOADING_TIMEOUT__SECONDS = 120.f;
+ if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS)
+ {
+ llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' "
+ << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) "
+ << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) "
+ << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) "
+ << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )."
+ << llendl;
+
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
+ mRuthTimer.reset();
+ }
+}
+
+BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
+{
+ // we wait a little bit before giving the all clear,
+ // to let textures settle down
+ const F32 PAUSE = 1.f;
+ if (loading)
+ mFullyLoadedTimer.reset();
+
+ mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE);
+
+ if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+ {
+ if (!mPreviousFullyLoaded && !loading && mFullyLoaded)
+ {
+ llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl;
+ LLSD args;
+ args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+ args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32());
+ args["NAME"] = getFullname();
+ LLNotificationsUtil::add("AvatarRezNotification",args);
+ }
+ }
+
+ // did our loading state "change" from last call?
+ const S32 UPDATE_RATE = 30;
+ BOOL changed =
+ ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call
+ (!mFullyLoadedInitialized) || // if we've never been called before
+ (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change
+
+ mPreviousFullyLoaded = mFullyLoaded;
+ mFullyLoadedInitialized = TRUE;
+ mFullyLoadedFrameCounter++;
+
+ return changed;
+}
+
+BOOL LLVOAvatar::isFullyLoaded() const
+{
+ if (gSavedSettings.getBOOL("RenderUnloadedAvatar"))
+ return TRUE;
+ else
+ return mFullyLoaded;
+}
+
+
+//-----------------------------------------------------------------------------
+// findMotion()
+//-----------------------------------------------------------------------------
+LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const
+{
+ return mMotionController.findMotion(id);
+}
+
+//-----------------------------------------------------------------------------
+// updateMeshTextures()
+// Uses the current TE values to set the meshes' and layersets' textures.
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateMeshTextures()
+{
+ // llinfos << "updateMeshTextures" << llendl;
+ // if user has never specified a texture, assign the default
+ for (U32 i=0; i < getNumTEs(); i++)
+ {
+ const LLViewerTexture* te_image = getImage(i, 0);
+ if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT))
+ {
+ setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR), 0); // IMG_DEFAULT_AVATAR = a special texture that's never rendered.
+ }
+ }
+
+ const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures
+ const BOOL other_culled = !isSelf() && mCulled;
+ LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
+ BOOL paused = FALSE;
+ if(!isSelf())
+ {
+ src_callback_list = &mCallbackTextureList ;
+ paused = mLoadedCallbacksPaused ;
+ }
+
+ std::vector<BOOL> is_layer_baked;
+ is_layer_baked.resize(mBakedTextureDatas.size(), false);
+
+ std::vector<BOOL> use_lkg_baked_layer; // lkg = "last known good"
+ use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false);
+
+ for (U32 i=0; i < mBakedTextureDatas.size(); i++)
+ {
+ is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
+
+ if (!other_culled)
+ {
+ // When an avatar is changing clothes and not in Appearance mode,
+ // use the last-known good baked texture until it finish the first
+ // render of the new layerset.
+ const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet
+ && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()
+ || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() );
+ use_lkg_baked_layer[i] = (!is_layer_baked[i]
+ && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR)
+ && layerset_invalid);
+ if (use_lkg_baked_layer[i])
+ {
+ mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE);
+ }
+ }
+ else
+ {
+ use_lkg_baked_layer[i] = (!is_layer_baked[i]
+ && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR);
+ if (mBakedTextureDatas[i].mTexLayerSet)
+ {
+ mBakedTextureDatas[i].mTexLayerSet->destroyComposite();
+ }
+ }
+
+ }
+
+ // Turn on alpha masking correctly for yourself and other avatars on 1.23+
+ mSupportsAlphaLayers = isSelf() || is_layer_baked[BAKED_HAIR];
+
+ // Baked textures should be requested from the sim this avatar is on. JC
+ const LLHost target_host = getObjectHost();
+ if (!target_host.isOk())
+ {
+ llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl;
+ }
+
+ for (U32 i=0; i < mBakedTextureDatas.size(); i++)
+ {
+ if (use_lkg_baked_layer[i] && !self_customizing )
+ {
+ LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host );
+ mBakedTextureDatas[i].mIsUsed = TRUE;
+ for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
+ {
+ mBakedTextureDatas[i].mMeshes[k]->setTexture( baked_img );
+ }
+ }
+ else if (!self_customizing && is_layer_baked[i])
+ {
+ LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
+ if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex )
+ {
+ // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing).
+ useBakedTexture( baked_img->getID() );
+ }
+ else
+ {
+ mBakedTextureDatas[i].mIsLoaded = FALSE;
+ if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
+ {
+ baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ),
+ src_callback_list, paused);
+ }
+ baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ),
+ src_callback_list, paused );
+ }
+ }
+ else if (mBakedTextureDatas[i].mTexLayerSet
+ && !other_culled)
+ {
+ mBakedTextureDatas[i].mTexLayerSet->createComposite();
+ mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE );
+ mBakedTextureDatas[i].mIsUsed = FALSE;
+ for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
+ {
+ mBakedTextureDatas[i].mMeshes[k]->setLayerSet( mBakedTextureDatas[i].mTexLayerSet );
+ }
+ }
+ }
+
+ // set texture and color of hair manually if we are not using a baked image.
+ // This can happen while loading hair for yourself, or for clients that did not
+ // bake a hair texture. Still needed for yourself after 1.22 is depricated.
+ if (!is_layer_baked[BAKED_HAIR] || self_customizing)
+ {
+ const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1);
+ LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 );
+ for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
+ {
+ mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] );
+ mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img );
+ }
+ }
+
+
+ for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin();
+ baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end();
+ ++baked_iter)
+ {
+ const EBakedTextureIndex baked_index = baked_iter->first;
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second;
+
+ for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+ local_tex_iter != baked_dict->mLocalTextures.end();
+ ++local_tex_iter)
+ {
+ const ETextureIndex texture_index = *local_tex_iter;
+ const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled;
+ if (isSelf())
+ {
+ setBakedReady(texture_index, is_baked_ready);
+ }
+ }
+ }
+ removeMissingBakedTextures();
+}
+
+// virtual
+//-----------------------------------------------------------------------------
+// setLocalTexture()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index )
+{
+ // invalid for anyone but self
+ llassert(0);
+}
+
+//virtual
+void LLVOAvatar::setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index)
+{
+ // invalid for anyone but self
+ llassert(0);
+}
+
+void LLVOAvatar::addChat(const LLChat& chat)
+{
+ std::deque<LLChat>::iterator chat_iter;
+
+ mChats.push_back(chat);
+
+ S32 chat_length = 0;
+ for( chat_iter = mChats.begin(); chat_iter != mChats.end(); ++chat_iter)
+ {
+ chat_length += chat_iter->mText.size();
+ }
+
+ // remove any excess chat
+ chat_iter = mChats.begin();
+ while ((chat_length > MAX_BUBBLE_CHAT_LENGTH || mChats.size() > MAX_BUBBLE_CHAT_UTTERANCES) && chat_iter != mChats.end())
+ {
+ chat_length -= chat_iter->mText.size();
+ mChats.pop_front();
+ chat_iter = mChats.begin();
+ }
+
+ mChatTimer.reset();
+}
+
+void LLVOAvatar::clearChat()
+{
+ mChats.clear();
+}
+
+// adds a morph mask to the appropriate baked texture structure
+void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer)
+{
+ if (index < BAKED_NUM_INDICES)
+ {
+ LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer);
+ mBakedTextureDatas[index].mMaskedMorphs.push_front(morph);
+ }
+}
+
+// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise
+BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index)
+{
+ if (index >= BAKED_NUM_INDICES)
+ {
+ return FALSE;
+ }
+
+ if (!mBakedTextureDatas[index].mMaskedMorphs.empty())
+ {
+ if (isSelf())
+ {
+ LLTexLayerSet *layer_set = mBakedTextureDatas[index].mTexLayerSet;
+ if (layer_set)
+ {
+ return !layer_set->isMorphValid();
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index)
+{
+ if (index >= BAKED_NUM_INDICES)
+ {
+ llwarns << "invalid baked texture index passed to applyMorphMask" << llendl;
+ return;
+ }
+
+ for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin();
+ iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter)
+ {
+ const LLMaskedMorph* maskedMorph = (*iter);
+ maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// releaseComponentTextures()
+// release any component texture UUIDs for which we have a baked texture
+// ! BACKWARDS COMPATIBILITY !
+// This is only called for non-self avatars, it can be taken out once component
+// textures aren't communicated by non-self avatars.
+//-----------------------------------------------------------------------------
+void LLVOAvatar::releaseComponentTextures()
+{
+ // ! BACKWARDS COMPATIBILITY !
+ // Detect if the baked hair texture actually wasn't sent, and if so set to default
+ if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED,0)->getID() == getImage(TEX_SKIRT_BAKED,0)->getID())
+ {
+ if (getImage(TEX_HAIR_BAKED,0)->getID() != IMG_INVISIBLE)
+ {
+ // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default
+ setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR);
+ }
+ }
+
+ for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+ {
+ const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
+ // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID
+ if (!isTextureDefined(bakedDicEntry->mTextureIndex)
+ && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ))
+ {
+ continue;
+ }
+
+ for (U8 texture = 0; texture < bakedDicEntry->mLocalTextures.size(); texture++)
+ {
+ const U8 te = (ETextureIndex)bakedDicEntry->mLocalTextures[texture];
+ setTETexture(te, IMG_DEFAULT_AVATAR);
+ }
+ }
+}
+
+//static
+BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name )
+{
+ switch( te )
+ {
+ case TEX_UPPER_SHIRT:
+ param_name[0] = 803; //"shirt_red";
+ param_name[1] = 804; //"shirt_green";
+ param_name[2] = 805; //"shirt_blue";
+ break;
+
+ case TEX_LOWER_PANTS:
+ param_name[0] = 806; //"pants_red";
+ param_name[1] = 807; //"pants_green";
+ param_name[2] = 808; //"pants_blue";
+ break;
+
+ case TEX_LOWER_SHOES:
+ param_name[0] = 812; //"shoes_red";
+ param_name[1] = 813; //"shoes_green";
+ param_name[2] = 817; //"shoes_blue";
+ break;
+
+ case TEX_LOWER_SOCKS:
+ param_name[0] = 818; //"socks_red";
+ param_name[1] = 819; //"socks_green";
+ param_name[2] = 820; //"socks_blue";
+ break;
+
+ case TEX_UPPER_JACKET:
+ case TEX_LOWER_JACKET:
+ param_name[0] = 834; //"jacket_red";
+ param_name[1] = 835; //"jacket_green";
+ param_name[2] = 836; //"jacket_blue";
+ break;
+
+ case TEX_UPPER_GLOVES:
+ param_name[0] = 827; //"gloves_red";
+ param_name[1] = 829; //"gloves_green";
+ param_name[2] = 830; //"gloves_blue";
+ break;
+
+ case TEX_UPPER_UNDERSHIRT:
+ param_name[0] = 821; //"undershirt_red";
+ param_name[1] = 822; //"undershirt_green";
+ param_name[2] = 823; //"undershirt_blue";
+ break;
+
+ case TEX_LOWER_UNDERPANTS:
+ param_name[0] = 824; //"underpants_red";
+ param_name[1] = 825; //"underpants_green";
+ param_name[2] = 826; //"underpants_blue";
+ break;
+
+ case TEX_SKIRT:
+ param_name[0] = 921; //"skirt_red";
+ param_name[1] = 922; //"skirt_green";
+ param_name[2] = 923; //"skirt_blue";
+ break;
+
+ case TEX_HEAD_TATTOO:
+ case TEX_LOWER_TATTOO:
+ case TEX_UPPER_TATTOO:
+ param_name[0] = 1071; //"tattoo_red";
+ param_name[1] = 1072; //"tattoo_green";
+ param_name[2] = 1073; //"tattoo_blue";
+ break;
+
+ default:
+ llassert(0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void LLVOAvatar::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake )
+{
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake );
+ setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake );
+ setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake );
+ }
+}
+
+LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te )
+{
+ LLColor4 color;
+ U32 param_name[3];
+ if( teToColorParams( te, param_name ) )
+ {
+ color.mV[VX] = getVisualParamWeight( param_name[0] );
+ color.mV[VY] = getVisualParamWeight( param_name[1] );
+ color.mV[VZ] = getVisualParamWeight( param_name[2] );
+ }
+ return color;
+}
+
+// static
+LLColor4 LLVOAvatar::getDummyColor()
+{
+ return DUMMY_COLOR;
+}
+
+void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const
+{
+ llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl;
+ for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++iter)
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+ // TODO: MULTI-WEARABLE: handle multiple textures for self
+ const LLViewerTexture* te_image = getImage(iter->first,0);
+ if( !te_image )
+ {
+ llinfos << " " << texture_dict->mName << ": null ptr" << llendl;
+ }
+ else if( te_image->getID().isNull() )
+ {
+ llinfos << " " << texture_dict->mName << ": null UUID" << llendl;
+ }
+ else if( te_image->getID() == IMG_DEFAULT )
+ {
+ llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl;
+ }
+ else if( te_image->getID() == IMG_DEFAULT_AVATAR )
+ {
+ llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl;
+ }
+ else
+ {
+ llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl;
+ }
+ }
+}
+
+// Unlike most wearable functions, this works for both self and other.
+BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
+{
+ if (mIsDummy) return TRUE;
+
+ switch(type)
+ {
+ case LLWearableType::WT_SHAPE:
+ case LLWearableType::WT_SKIN:
+ case LLWearableType::WT_HAIR:
+ case LLWearableType::WT_EYES:
+ return TRUE; // everyone has all bodyparts
+ default:
+ break; // Do nothing
+ }
+
+ /* switch(type)
+ case LLWearableType::WT_SHIRT:
+ indicator_te = TEX_UPPER_SHIRT; */
+ for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++tex_iter)
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second;
+ if (texture_dict->mWearableType == type)
+ {
+ // If you're checking another avatar's clothing, you don't have component textures.
+ // Thus, you must check to see if the corresponding baked texture is defined.
+ // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
+ // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
+ // gets baked into a texture that always exists (upper or lower).
+ if (texture_dict->mIsUsedByBakedTexture)
+ {
+ const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+ return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
+ }
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// clampAttachmentPositions()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::clampAttachmentPositions()
+{
+ if (isDead())
+ {
+ return;
+ }
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (attachment)
+ {
+ attachment->clampObjectPosition();
+ }
+ }
+}
+
+BOOL LLVOAvatar::hasHUDAttachment() const
+{
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+LLBBox LLVOAvatar::getHUDBBox() const
+{
+ LLBBox bbox;
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (attachment->getIsHUDAttachment())
+ {
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object == NULL)
+ {
+ llwarns << "HUD attached object is NULL!" << llendl;
+ continue;
+ }
+ // initialize bounding box to contain identity orientation and center point for attached object
+ bbox.addPointLocal(attached_object->getPosition());
+ // add rotated bounding box for attached object
+ bbox.addBBoxAgent(attached_object->getBoundingBoxAgent());
+ LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end();
+ ++iter)
+ {
+ const LLViewerObject* child_objectp = *iter;
+ bbox.addBBoxAgent(child_objectp->getBoundingBoxAgent());
+ }
+ }
+ }
+ }
+
+ return bbox;
+}
+
+void LLVOAvatar::rebuildHUD()
+{
+}
+
+//-----------------------------------------------------------------------------
+// onFirstTEMessageReceived()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::onFirstTEMessageReceived()
+{
+ if( !mFirstTEMessageReceived )
+ {
+ mFirstTEMessageReceived = TRUE;
+
+ LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
+ BOOL paused = FALSE ;
+ if(!isSelf())
+ {
+ src_callback_list = &mCallbackTextureList ;
+ paused = mLoadedCallbacksPaused ;
+ }
+
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
+
+ // Use any baked textures that we have even if they haven't downloaded yet.
+ // (That is, don't do a transition from unbaked to baked.)
+ if (layer_baked)
+ {
+ LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
+ mBakedTextureDatas[i].mLastTextureIndex = image->getID();
+ // If we have more than one texture for the other baked layers, we'll want to call this for them too.
+ if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
+ {
+ image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ),
+ src_callback_list, paused);
+ }
+ image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ),
+ src_callback_list, paused );
+ }
+ }
+
+ mMeshTexturesDirty = TRUE;
+ gPipeline.markGLRebuild(this);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// bool visualParamWeightsAreDefault()
+//-----------------------------------------------------------------------------
+bool LLVOAvatar::visualParamWeightsAreDefault()
+{
+ bool rtn = true;
+
+ bool is_wearing_skirt = isWearingWearableType(LLWearableType::WT_SKIRT);
+ for (LLVisualParam *param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ if (param->isTweakable())
+ {
+ LLViewerVisualParam* vparam = dynamic_cast<LLViewerVisualParam*>(param);
+ llassert(vparam);
+ bool is_skirt_param = vparam &&
+ LLWearableType::WT_SKIRT == vparam->getWearableType();
+ if (param->getWeight() != param->getDefaultWeight() &&
+ // we have to not care whether skirt weights are default, if we're not actually wearing a skirt
+ (is_wearing_skirt || !is_skirt_param))
+ {
+ //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl;
+ rtn = false;
+ break;
+ }
+ }
+ }
+
+ //llinfos << "params are default ? " << int(rtn) << llendl;
+
+ return rtn;
+}
+
+
+//-----------------------------------------------------------------------------
+// processAvatarAppearance()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
+{
+ if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages"))
+ {
+ llwarns << "Blocking AvatarAppearance message" << llendl;
+ return;
+ }
+
+ LLMemType mt(LLMemType::MTYPE_AVATAR);
+
+// llinfos << "processAvatarAppearance start " << mID << llendl;
+ BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
+
+ mFirstAppearanceMessageReceived = TRUE;
+
+ if( isSelf() )
+ {
+ llwarns << "Received AvatarAppearance for self" << llendl;
+ if( mFirstTEMessageReceived )
+ {
+// llinfos << "processAvatarAppearance end " << mID << llendl;
+ return;
+ }
+ }
+
+ ESex old_sex = getSex();
+
+// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl;
+// dumpAvatarTEs( "PRE processAvatarAppearance()" );
+ unpackTEMessage(mesgsys, _PREHASH_ObjectData);
+// dumpAvatarTEs( "POST processAvatarAppearance()" );
+
+ // prevent the overwriting of valid baked textures with invalid baked textures
+ for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++)
+ {
+ if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex)
+ && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT
+ && baked_index != BAKED_SKIRT)
+ {
+ setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,
+ LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+ }
+ }
+
+
+ if( !is_first_appearance_message )
+ {
+ onFirstTEMessageReceived();
+ }
+
+ setCompositeUpdatesEnabled( FALSE );
+ mMeshTexturesDirty = TRUE;
+ gPipeline.markGLRebuild(this);
+
+ // ! BACKWARDS COMPATIBILITY !
+ // Non-self avatars will no longer have component textures
+ if (!isSelf())
+ {
+ releaseComponentTextures();
+ }
+
+ // parse visual params
+ S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
+ bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
+ if( num_blocks > 1 && !drop_visual_params_debug)
+ {
+ BOOL params_changed = FALSE;
+ BOOL interp_params = FALSE;
+
+ LLVisualParam* param = getFirstVisualParam();
+ llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
+ if (!param)
+ {
+ llwarns << "No visual params!" << llendl;
+ }
+ else
+ {
+ for( S32 i = 0; i < num_blocks; i++ )
+ {
+ while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ {
+ param = getNextVisualParam();
+ }
+
+ if( !param )
+ {
+ // more visual params supplied than expected - just process what we know about
+ break;
+ }
+
+ U8 value;
+ mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i);
+ F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight());
+
+ if (is_first_appearance_message || (param->getWeight() != newWeight))
+ {
+ //llinfos << "Received update for param " << param->getDisplayName() << " at value " << newWeight << llendl;
+ params_changed = TRUE;
+ if(is_first_appearance_message)
+ {
+ param->setWeight(newWeight, FALSE);
+ }
+ else
+ {
+ interp_params = TRUE;
+ param->setAnimationTarget(newWeight, FALSE);
+ }
+ }
+ param = getNextVisualParam();
+ }
+ }
+
+ const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+ if (num_blocks != expected_tweakable_count)
+ {
+ llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl;
+ }
+
+ if (params_changed)
+ {
+ if (interp_params)
+ {
+ startAppearanceAnimation();
+ }
+ updateVisualParams();
+
+ ESex new_sex = getSex();
+ if( old_sex != new_sex )
+ {
+ updateSexDependentLayerSets( FALSE );
+ }
+ }
+
+ llassert( getSex() == ((getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE) );
+ }
+ else
+ {
+ // AvatarAppearance message arrived without visual params
+ if (drop_visual_params_debug)
+ {
+ llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl;
+ }
+ else
+ {
+ llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
+ }
+
+ const F32 LOADING_TIMEOUT_SECONDS = 60.f;
+ // this isn't really a problem if we already have a non-default shape
+ if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS)
+ {
+ // re-request appearance, hoping that it comes back with a shape next time
+ llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl;
+ LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
+ mRuthTimer.reset();
+ }
+ else
+ {
+ llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl;
+ // we don't really care.
+ }
+ }
+
+ setCompositeUpdatesEnabled( TRUE );
+
+ // If all of the avatars are completely baked, release the global image caches to conserve memory.
+ LLVOAvatar::cullAvatarsByPixelArea();
+
+// llinfos << "processAvatarAppearance end " << mID << llendl;
+}
+
+// static
+void LLVOAvatar::getAnimLabels( LLDynamicArray<std::string>* labels )
+{
+ S32 i;
+ for( i = 0; i < gUserAnimStatesCount; i++ )
+ {
+ labels->put( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) );
+ }
+
+ // Special case to trigger away (AFK) state
+ labels->put( "Away From Keyboard" );
+}
+
+// static
+void LLVOAvatar::getAnimNames( LLDynamicArray<std::string>* names )
+{
+ S32 i;
+
+ for( i = 0; i < gUserAnimStatesCount; i++ )
+ {
+ names->put( std::string(gUserAnimStates[i].mName) );
+ }
+
+ // Special case to trigger away (AFK) state
+ names->put( "enter_away_from_keyboard_state" );
+}
+
+void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
+{
+ if (!userdata) return;
+
+ //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl;
+ const LLMemType mt(LLMemType::MTYPE_AVATAR);
+ const LLUUID id = src_vi->getID();
+
+ LLTextureMaskData* maskData = (LLTextureMaskData*) userdata;
+ LLVOAvatar* self = (LLVOAvatar*) gObjectList.findObject( maskData->mAvatarID );
+
+ // if discard level is 2 less than last discard level we processed, or we hit 0,
+ // then generate morph masks
+ if(self && success && (discard_level < maskData->mLastDiscardLevel - 2 || discard_level == 0))
+ {
+ if(aux_src && aux_src->getComponents() == 1)
+ {
+ if (!aux_src->getData())
+ {
+ llerrs << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl;
+ return;
+ }
+
+ U32 gl_name;
+ LLImageGL::generateTextures(1, &gl_name );
+ stop_glerror();
+
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
+ stop_glerror();
+
+ LLImageGL::setManualImage(
+ GL_TEXTURE_2D, 0, GL_ALPHA8,
+ aux_src->getWidth(), aux_src->getHeight(),
+ GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData());
+ stop_glerror();
+
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+
+ /* if( id == head_baked->getID() )
+ if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet)
+ //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl;
+ self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1);
+ maskData->mLastDiscardLevel = discard_level; */
+ BOOL found_texture_id = false;
+ for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++iter)
+ {
+
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+ if (texture_dict->mIsUsedByBakedTexture)
+ {
+ const ETextureIndex texture_index = iter->first;
+ const LLViewerTexture *baked_img = self->getImage(texture_index, 0);
+ if (baked_img && id == baked_img->getID())
+ {
+ const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+ self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index);
+ maskData->mLastDiscardLevel = discard_level;
+ if (self->mBakedTextureDatas[baked_index].mMaskTexName)
+ {
+ LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName));
+ }
+ self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name;
+ found_texture_id = true;
+ break;
+ }
+ }
+ }
+ if (!found_texture_id)
+ {
+ llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl;
+ }
+ self->dirtyMesh();
+ }
+ else
+ {
+ // this can happen when someone uses an old baked texture possibly provided by
+ // viewer-side baked texture caching
+ llwarns << "Masks loaded callback but NO aux source!" << llendl;
+ }
+ }
+
+ if (final || !success)
+ {
+ delete maskData;
+ }
+}
+
+// static
+void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata )
+{
+ LLUUID *avatar_idp = (LLUUID *)userdata;
+ LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
+
+ if (!success && selfp)
+ {
+ selfp->removeMissingBakedTextures();
+ }
+ if (final || !success )
+ {
+ delete avatar_idp;
+ }
+}
+
+void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)
+{
+ //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl;
+
+ LLUUID id = src_vi->getID();
+ LLUUID *avatar_idp = (LLUUID *)userdata;
+ LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
+
+ if (selfp && !success)
+ {
+ selfp->removeMissingBakedTextures();
+ }
+
+ if( final || !success )
+ {
+ delete avatar_idp;
+ }
+
+ if( selfp && success && final )
+ {
+ selfp->useBakedTexture( id );
+ }
+}
+
+
+// Called when baked texture is loaded and also when we start up with a baked texture
+void LLVOAvatar::useBakedTexture( const LLUUID& id )
+{
+ /* if(id == head_baked->getID())
+ mHeadBakedLoaded = TRUE;
+ mLastHeadBakedID = id;
+ mHeadMesh0.setTexture( head_baked );
+ mHeadMesh1.setTexture( head_baked ); */
+ for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+ {
+ LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 );
+ if (id == image_baked->getID())
+ {
+ mBakedTextureDatas[i].mIsLoaded = true;
+ mBakedTextureDatas[i].mLastTextureIndex = id;
+ mBakedTextureDatas[i].mIsUsed = true;
+ for (U32 k = 0; k < mBakedTextureDatas[i].mMeshes.size(); k++)
+ {
+ mBakedTextureDatas[i].mMeshes[k]->setTexture( image_baked );
+ }
+ if (mBakedTextureDatas[i].mTexLayerSet)
+ {
+ //mBakedTextureDatas[i].mTexLayerSet->destroyComposite();
+ }
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
+ for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+ local_tex_iter != baked_dict->mLocalTextures.end();
+ ++local_tex_iter)
+ {
+ if (isSelf()) setBakedReady(*local_tex_iter, TRUE);
+ }
+
+ // ! BACKWARDS COMPATIBILITY !
+ // Workaround for viewing avatars from old viewers that haven't baked hair textures.
+ // This is paired with similar code in updateMeshTextures that sets hair mesh color.
+ if (i == BAKED_HAIR)
+ {
+ for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++)
+ {
+ mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f );
+ }
+ }
+ }
+ }
+
+ dirtyMesh();
+}
+
+// static
+void LLVOAvatar::dumpArchetypeXML( void* )
+{
+ LLAPRFile outfile;
+ outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
+ apr_file_t* file = outfile.getFileHandle() ;
+ if (!file)
+ {
+ return;
+ }
+
+ apr_file_printf( file, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n" );
+ apr_file_printf( file, "<linden_genepool version=\"1.0\">\n" );
+ apr_file_printf( file, "\n\t<archetype name=\"???\">\n" );
+
+ // only body parts, not clothing.
+ for (S32 type = LLWearableType::WT_SHAPE; type <= LLWearableType::WT_EYES; type++)
+ {
+ const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
+ apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
+
+ for (LLVisualParam* param = gAgentAvatarp->getFirstVisualParam(); param; param = gAgentAvatarp->getNextVisualParam())
+ {
+ LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
+ if( (viewer_param->getWearableType() == type) &&
+ (viewer_param->isTweakable() ) )
+ {
+ apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\"/>\n",
+ viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight());
+ }
+ }
+
+ for (U8 te = 0; te < TEX_NUM_INDICES; te++)
+ {
+ if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te) == type)
+ {
+ // MULTIPLE_WEARABLES: extend to multiple wearables?
+ LLViewerTexture* te_image = ((LLVOAvatar *)(gAgentAvatarp))->getImage((ETextureIndex)te, 0);
+ if( te_image )
+ {
+ std::string uuid_str;
+ te_image->getID().toString( uuid_str );
+ apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
+ }
+ }
+ }
+ }
+ apr_file_printf( file, "\t</archetype>\n" );
+ apr_file_printf( file, "\n</linden_genepool>\n" );
+}
+
+
+void LLVOAvatar::setVisibilityRank(U32 rank)
+{
+ if (mDrawable.isNull() || mDrawable->isDead())
+ {
+ // do nothing
+ return;
+ }
+ mVisibilityRank = rank;
+}
+
+// Assumes LLVOAvatar::sInstances has already been sorted.
+S32 LLVOAvatar::getUnbakedPixelAreaRank()
+{
+ S32 rank = 1;
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* inst = (LLVOAvatar*) *iter;
+ if (inst == this)
+ {
+ return rank;
+ }
+ else if (!inst->isDead() && !inst->isFullyBaked())
+ {
+ rank++;
+ }
+ }
+
+ llassert(0);
+ return 0;
+}
+
+struct CompareScreenAreaGreater
+{
+ BOOL operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs)
+ {
+ return lhs->getPixelArea() > rhs->getPixelArea();
+ }
+};
+
+// static
+void LLVOAvatar::cullAvatarsByPixelArea()
+{
+ std::sort(LLCharacter::sInstances.begin(), LLCharacter::sInstances.end(), CompareScreenAreaGreater());
+
+ // Update the avatars that have changed status
+ U32 rank = 2; //1 is reserved for self.
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* inst = (LLVOAvatar*) *iter;
+ BOOL culled;
+ if (inst->isSelf() || inst->isFullyBaked())
+ {
+ culled = FALSE;
+ }
+ else
+ {
+ culled = TRUE;
+ }
+
+ if (inst->mCulled != culled)
+ {
+ inst->mCulled = culled;
+ lldebugs << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << llendl;
+ inst->updateMeshTextures();
+ }
+
+ if (inst->isSelf())
+ {
+ inst->setVisibilityRank(1);
+ }
+ else if (inst->mDrawable.notNull() && inst->mDrawable->isVisible())
+ {
+ inst->setVisibilityRank(rank++);
+ }
+ }
+
+ S32 grey_avatars = 0;
+ if (LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars))
+ {
+ LLVOAvatar::deleteCachedImages(false);
+ }
+ else
+ {
+ if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame
+ {
+ sUnbakedUpdateTime = gFrameTimeSeconds;
+ sUnbakedTime += gFrameIntervalSeconds;
+ }
+ if (grey_avatars > 0)
+ {
+ if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame
+ {
+ sGreyUpdateTime = gFrameTimeSeconds;
+ sGreyTime += gFrameIntervalSeconds;
+ }
+ }
+ }
+}
+
+void LLVOAvatar::startAppearanceAnimation()
+{
+ if(!mAppearanceAnimating)
+ {
+ mAppearanceAnimating = TRUE;
+ mAppearanceMorphTimer.reset();
+ mLastAppearanceBlendTime = 0.f;
+ }
+}
+
+// virtual
+void LLVOAvatar::removeMissingBakedTextures()
+{
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatarXmlInfo
+//-----------------------------------------------------------------------------
+
+LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo()
+ : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
+{
+}
+
+LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo()
+{
+ std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
+ std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
+ std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
+ deleteAndClear(mTexSkinColorInfo);
+ deleteAndClear(mTexHairColorInfo);
+ deleteAndClear(mTexEyeColorInfo);
+ std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+ std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatarBoneInfo::parseXml()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
+{
+ if (node->hasName("bone"))
+ {
+ mIsJoint = TRUE;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ llwarns << "Bone without name" << llendl;
+ return FALSE;
+ }
+ }
+ else if (node->hasName("collision_volume"))
+ {
+ mIsJoint = FALSE;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!node->getFastAttributeString(name_string, mName))
+ {
+ mName = "Collision Volume";
+ }
+ }
+ else
+ {
+ llwarns << "Invalid node " << node->getName() << llendl;
+ return FALSE;
+ }
+
+ static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+ if (!node->getFastAttributeVector3(pos_string, mPos))
+ {
+ llwarns << "Bone without position" << llendl;
+ return FALSE;
+ }
+
+ static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
+ if (!node->getFastAttributeVector3(rot_string, mRot))
+ {
+ llwarns << "Bone without rotation" << llendl;
+ return FALSE;
+ }
+
+ static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+ if (!node->getFastAttributeVector3(scale_string, mScale))
+ {
+ llwarns << "Bone without scale" << llendl;
+ return FALSE;
+ }
+
+ if (mIsJoint)
+ {
+ static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
+ if (!node->getFastAttributeVector3(pivot_string, mPivot))
+ {
+ llwarns << "Bone without pivot" << llendl;
+ return FALSE;
+ }
+ }
+
+ // parse children
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLVOAvatarBoneInfo *child_info = new LLVOAvatarBoneInfo;
+ if (!child_info->parseXml(child))
+ {
+ delete child_info;
+ return FALSE;
+ }
+ mChildList.push_back(child_info);
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLVOAvatarSkeletonInfo::parseXml()
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
+{
+ static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
+ if (!node->getFastAttributeS32(num_bones_string, mNumBones))
+ {
+ llwarns << "Couldn't find number of bones." << llendl;
+ return FALSE;
+ }
+
+ static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
+ node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
+
+ LLXmlTreeNode* child;
+ for( child = node->getFirstChild(); child; child = node->getNextChild() )
+ {
+ LLVOAvatarBoneInfo *info = new LLVOAvatarBoneInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ llwarns << "Error parsing bone in skeleton file" << llendl;
+ return FALSE;
+ }
+ mBoneInfoList.push_back(info);
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* node = root->getChildByName( "skeleton" );
+ if( !node )
+ {
+ llwarns << "avatar file: missing <skeleton>" << llendl;
+ return FALSE;
+ }
+
+ LLXmlTreeNode* child;
+
+ // SKELETON DISTORTIONS
+ for (child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_skeleton"))
+ {
+ if (child->getChildByName("param_morph"))
+ {
+ llwarns << "Can't specify morph param in skeleton definition." << llendl;
+ }
+ else
+ {
+ llwarns << "Unknown param type." << llendl;
+ }
+ continue;
+ }
+
+ LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
+ if (!info->parseXml(child))
+ {
+ delete info;
+ return FALSE;
+ }
+
+ mSkeletalDistortionInfoList.push_back(info);
+ }
+
+ // ATTACHMENT POINTS
+ for (child = node->getChildByName( "attachment_point" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ LLVOAvatarAttachmentInfo* info = new LLVOAvatarAttachmentInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (!child->getFastAttributeString(name_string, info->mName))
+ {
+ llwarns << "No name supplied for attachment point." << llendl;
+ delete info;
+ continue;
+ }
+
+ static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
+ if (!child->getFastAttributeString(joint_string, info->mJointName))
+ {
+ llwarns << "No bone declared in attachment point " << info->mName << llendl;
+ delete info;
+ continue;
+ }
+
+ static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
+ if (child->getFastAttributeVector3(position_string, info->mPosition))
+ {
+ info->mHasPosition = TRUE;
+ }
+
+ static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
+ if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
+ {
+ info->mHasRotation = TRUE;
+ }
+ static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
+ if (child->getFastAttributeS32(group_string, info->mGroup))
+ {
+ if (info->mGroup == -1)
+ info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
+ }
+
+ static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+ if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
+ {
+ llwarns << "No id supplied for attachment point " << info->mName << llendl;
+ delete info;
+ continue;
+ }
+
+ static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
+ child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
+
+ static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
+ child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
+
+ static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
+ child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
+
+ mAttachmentInfoList.push_back(info);
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
+ node;
+ node = root->getNextNamedChild())
+ {
+ LLVOAvatarMeshInfo *info = new LLVOAvatarMeshInfo;
+
+ // attribute: type
+ static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
+ if( !node->getFastAttributeString( type_string, info->mType ) )
+ {
+ llwarns << "Avatar file: <mesh> is missing type attribute. Ignoring element. " << llendl;
+ delete info;
+ return FALSE; // Ignore this element
+ }
+
+ static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
+ if (!node->getFastAttributeS32( lod_string, info->mLOD ))
+ {
+ llwarns << "Avatar file: <mesh> is missing lod attribute. Ignoring element. " << llendl;
+ delete info;
+ return FALSE; // Ignore this element
+ }
+
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
+ {
+ llwarns << "Avatar file: <mesh> is missing file_name attribute. Ignoring: " << info->mType << llendl;
+ delete info;
+ return FALSE; // Ignore this element
+ }
+
+ static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
+ node->getFastAttributeString( reference_string, info->mReferenceMeshName );
+
+ // attribute: min_pixel_area
+ static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
+ static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
+ if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
+ {
+ F32 min_pixel_area = 0.1f;
+ if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
+ {
+ // this is square root of pixel area (sensible to use linear space in defining lods)
+ min_pixel_area = min_pixel_area * min_pixel_area;
+ }
+ info->mMinPixelArea = min_pixel_area;
+ }
+
+ // Parse visual params for this node only if we haven't already
+ for (LLXmlTreeNode* child = node->getChildByName( "param" );
+ child;
+ child = node->getNextNamedChild())
+ {
+ if (!child->getChildByName("param_morph"))
+ {
+ if (child->getChildByName("param_skeleton"))
+ {
+ llwarns << "Can't specify skeleton param in a mesh definition." << llendl;
+ }
+ else
+ {
+ llwarns << "Unknown param type." << llendl;
+ }
+ continue;
+ }
+
+ LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
+ if (!morphinfo->parseXml(child))
+ {
+ delete morphinfo;
+ delete info;
+ return -1;
+ }
+ BOOL shared = FALSE;
+ static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
+ child->getFastAttributeBOOL(shared_string, shared);
+
+ info->mPolyMorphTargetInfoList.push_back(LLVOAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
+ }
+
+ mMeshInfoList.push_back(info);
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlColorNodes(): parses <global_color> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
+ color_node;
+ color_node = root->getNextNamedChild())
+ {
+ std::string global_color_name;
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+ if (color_node->getFastAttributeString( name_string, global_color_name ) )
+ {
+ if( global_color_name == "skin_color" )
+ {
+ if (mTexSkinColorInfo)
+ {
+ llwarns << "avatar file: multiple instances of skin_color" << llendl;
+ return FALSE;
+ }
+ mTexSkinColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexSkinColorInfo->parseXml( color_node ) )
+ {
+ deleteAndClear(mTexSkinColorInfo);
+ llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl;
+ return FALSE;
+ }
+ }
+ else if( global_color_name == "hair_color" )
+ {
+ if (mTexHairColorInfo)
+ {
+ llwarns << "avatar file: multiple instances of hair_color" << llendl;
+ return FALSE;
+ }
+ mTexHairColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexHairColorInfo->parseXml( color_node ) )
+ {
+ deleteAndClear(mTexHairColorInfo);
+ llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl;
+ return FALSE;
+ }
+ }
+ else if( global_color_name == "eye_color" )
+ {
+ if (mTexEyeColorInfo)
+ {
+ llwarns << "avatar file: multiple instances of eye_color" << llendl;
+ return FALSE;
+ }
+ mTexEyeColorInfo = new LLTexGlobalColorInfo;
+ if( !mTexEyeColorInfo->parseXml( color_node ) )
+ {
+ llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl;
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
+{
+ for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
+ layer_node;
+ layer_node = root->getNextNamedChild())
+ {
+ LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
+ if( layer_info->parseXml( layer_node ) )
+ {
+ mLayerInfoList.push_back(layer_info);
+ }
+ else
+ {
+ delete layer_info;
+ llwarns << "avatar file: layer_set->parseXml() failed" << llendl;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
+ if( driver )
+ {
+ for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
+ grand_child;
+ grand_child = driver->getNextNamedChild())
+ {
+ if( grand_child->getChildByName( "param_driver" ) )
+ {
+ LLDriverParamInfo* driver_info = new LLDriverParamInfo();
+ if( driver_info->parseXml( grand_child ) )
+ {
+ mDriverInfoList.push_back(driver_info);
+ }
+ else
+ {
+ delete driver_info;
+ llwarns << "avatar file: driver_param->parseXml() failed" << llendl;
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
+{
+ LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
+ if( !masks )
+ {
+ return FALSE;
+ }
+
+ for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
+ grand_child;
+ grand_child = masks->getNextNamedChild())
+ {
+ LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo();
+
+ static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
+ if (!grand_child->getFastAttributeString(name_string, info->mName))
+ {
+ llwarns << "No name supplied for morph mask." << llendl;
+ delete info;
+ continue;
+ }
+
+ static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
+ if (!grand_child->getFastAttributeString(region_string, info->mRegion))
+ {
+ llwarns << "No region supplied for morph mask." << llendl;
+ delete info;
+ continue;
+ }
+
+ static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
+ if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
+ {
+ llwarns << "No layer supplied for morph mask." << llendl;
+ delete info;
+ continue;
+ }
+
+ // optional parameter. don't throw a warning if not present.
+ static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
+ grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
+
+ mMorphMaskInfoList.push_back(info);
+ }
+
+ return TRUE;
+}
+
+//virtual
+void LLVOAvatar::updateRegion(LLViewerRegion *regionp)
+{
+ LLViewerObject::updateRegion(regionp);
+}
+
+std::string LLVOAvatar::getFullname() const
+{
+ std::string name;
+
+ LLNameValue* first = getNVPair("FirstName");
+ LLNameValue* last = getNVPair("LastName");
+ if (first && last)
+ {
+ name = LLCacheName::buildFullName( first->getString(), last->getString() );
+ }
+
+ return name;
+}
+
+LLHost LLVOAvatar::getObjectHost() const
+{
+ LLViewerRegion* region = getRegion();
+ if (region && !isDead())
+ {
+ return region->getHost();
+ }
+ else
+ {
+ return LLHost::invalid;
+ }
+}
+
+//static
+void LLVOAvatar::updateFreezeCounter(S32 counter)
+{
+ if(counter)
+ {
+ sFreezeCounter = counter;
+ }
+ else if(sFreezeCounter > 0)
+ {
+ sFreezeCounter--;
+ }
+ else
+ {
+ sFreezeCounter = 0;
+ }
+}
+
+BOOL LLVOAvatar::updateLOD()
+{
+ if (isImpostor())
+ {
+ return TRUE;
+ }
+
+ BOOL res = updateJointLODs();
+
+ LLFace* facep = mDrawable->getFace(0);
+ if (!facep->getVertexBuffer())
+ {
+ dirtyMesh(2);
+ }
+
+ if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
+ { //LOD changed or new mesh created, allocate new vertex buffer if needed
+ updateMeshData();
+ mDirtyMesh = 0;
+ mNeedsSkin = TRUE;
+ mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
+ }
+ updateVisibility();
+
+ return res;
+}
+
+void LLVOAvatar::updateLODRiggedAttachments( void )
+{
+ updateLOD();
+ rebuildRiggedAttachments();
+}
+U32 LLVOAvatar::getPartitionType() const
+{
+ // Avatars merely exist as drawables in the bridge partition
+ return LLViewerRegion::PARTITION_BRIDGE;
+}
+
+//static
+void LLVOAvatar::updateImpostors()
+{
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*) *iter;
+ if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor())
+ {
+ gPipeline.generateImpostor(avatar);
+ }
+ }
+}
+
+BOOL LLVOAvatar::isImpostor() const
+{
+ return (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD) ? TRUE : FALSE;
+}
+
+
+BOOL LLVOAvatar::needsImpostorUpdate() const
+{
+ return mNeedsImpostorUpdate;
+}
+
+const LLVector3& LLVOAvatar::getImpostorOffset() const
+{
+ return mImpostorOffset;
+}
+
+const LLVector2& LLVOAvatar::getImpostorDim() const
+{
+ return mImpostorDim;
+}
+
+void LLVOAvatar::setImpostorDim(const LLVector2& dim)
+{
+ mImpostorDim = dim;
+}
+
+void LLVOAvatar::cacheImpostorValues()
+{
+ getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance);
+}
+
+void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const
+{
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+ extents[0] = ext[0];
+ extents[1] = ext[1];
+
+ LLVector3 at = LLViewerCamera::getInstance()->getOrigin()-(getRenderPosition()+mImpostorOffset);
+ distance = at.normalize();
+ F32 da = 1.f - (at*LLViewerCamera::getInstance()->getAtAxis());
+ angle.mV[0] = LLViewerCamera::getInstance()->getYaw()*da;
+ angle.mV[1] = LLViewerCamera::getInstance()->getPitch()*da;
+ angle.mV[2] = da;
+}
+
+void LLVOAvatar::idleUpdateRenderCost()
+{
+ static const U32 ARC_BODY_PART_COST = 20;
+ static const U32 ARC_LIMIT = 2048;
+
+ static std::set<LLUUID> all_textures;
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+ {
+ return;
+ }
+
+ U32 cost = 0;
+ std::set<LLUUID> textures;
+
+ for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+ {
+ const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
+ ETextureIndex tex_index = baked_dict->mTextureIndex;
+ if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
+ {
+ if (isTextureVisible(tex_index))
+ {
+ cost +=ARC_BODY_PART_COST;
+ }
+ }
+ }
+
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object && !attached_object->isHUDAttachment())
+ {
+ const LLDrawable* drawable = attached_object->mDrawable;
+ if (drawable)
+ {
+ const LLVOVolume* volume = drawable->getVOVolume();
+ if (volume)
+ {
+ cost += volume->getRenderCost(textures);
+ }
+ }
+ }
+ }
+
+ }
+
+ // Diagnostic output to identify all avatar-related textures.
+ // Does not affect rendering cost calculation.
+ // Could be wrapped in a debug option if output becomes problematic.
+ if (isSelf())
+ {
+ // print any attachment textures we didn't already know about.
+ for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it)
+ {
+ LLUUID image_id = *it;
+ if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+ continue;
+ if (all_textures.find(image_id) == all_textures.end())
+ {
+ // attachment texture not previously seen.
+ llinfos << "attachment_texture: " << image_id.asString() << llendl;
+ all_textures.insert(image_id);
+ }
+ }
+
+ // print any avatar textures we didn't already know about
+ for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++iter)
+ {
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+ // TODO: MULTI-WEARABLE: handle multiple textures for self
+ const LLViewerTexture* te_image = getImage(iter->first,0);
+ if (!te_image)
+ continue;
+ LLUUID image_id = te_image->getID();
+ if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+ continue;
+ if (all_textures.find(image_id) == all_textures.end())
+ {
+ llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
+ all_textures.insert(image_id);
+ }
+ }
+ }
+
+ cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST;
+
+ setDebugText(llformat("%d", cost));
+ F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
+ F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f);
+ mText->setColor(LLColor4(red,green,0,1));
+}
+
+// static
+BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index)
+{
+ if (index < 0 || index >= TEX_NUM_INDICES) return false;
+ return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsLocalTexture;
+}
+
+// static
+BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index)
+{
+ if (index < 0 || index >= TEX_NUM_INDICES) return false;
+ return LLVOAvatarDictionary::getInstance()->getTexture(index)->mIsBakedTexture;
+}
+
+const std::string LLVOAvatar::getBakedStatusForPrintout() const
+{
+ std::string line;
+
+ for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+ iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+ ++iter)
+ {
+ const ETextureIndex index = iter->first;
+ const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+ if (texture_dict->mIsBakedTexture)
+ {
+ line += texture_dict->mName;
+ if (isTextureDefined(index))
+ {
+ line += "_baked";
+ }
+ line += " ";
+ }
+ }
+ return line;
+}
+
+
+
+//virtual
+S32 LLVOAvatar::getTexImageSize() const
+{
+ return TEX_IMAGE_SIZE_OTHER;
+}
+
+//-----------------------------------------------------------------------------
+// Utility functions
+//-----------------------------------------------------------------------------
+
+F32 calc_bouncy_animation(F32 x)
+{
+ return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f;
+}
+
+//virtual
+BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const
+{
+ if (isIndexLocalTexture(te))
+ {
+ return FALSE;
+ }
+
+ return (getImage(te, index)->getID() != IMG_DEFAULT_AVATAR &&
+ getImage(te, index)->getID() != IMG_DEFAULT);
+}
+
+//virtual
+BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index) const
+{
+ if (isIndexLocalTexture(type))
+ {
+ return isTextureDefined(type, index);
+ }
+ else
+ {
+ // baked textures can use TE images directly
+ return ((isTextureDefined(type) || isSelf())
+ && (getTEImage(type)->getID() != IMG_INVISIBLE
+ || LLDrawPoolAlpha::sShowDebugAlpha));
+ }
+}
+
+//virtual
+BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const
+{
+ // non-self avatars don't have wearables
+ return FALSE;
+}
+
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 4a605b6c55..59883e0bb1 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2523,10 +2523,6 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const
//------------------------------------------------------------------------
BOOL LLVOAvatarSelf::needsRenderBeam()
{
- if (gNoRender)
- {
- return FALSE;
- }
LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing());
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index d239347810..4b3a9a4dc3 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -72,6 +72,8 @@ LLWaterParamManager::LLWaterParamManager() :
mWave1Dir(.5f, .5f, "wave1Dir"),
mWave2Dir(.5f, .5f, "wave2Dir"),
mDensitySliderValue(1.0f),
+ mPrevFogDensity(16.0f), // 2^4
+ mPrevFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f),
mWaterFogKS(1.0f)
{
}
@@ -265,6 +267,20 @@ void LLWaterParamManager::update(LLViewerCamera * cam)
// update the shaders and the menu
propagateParameters();
+ // If water fog color has been changed, save it.
+ if (mPrevFogColor != mFogColor)
+ {
+ gSavedSettings.setColor4("WaterFogColor", mFogColor);
+ mPrevFogColor = mFogColor;
+ }
+
+ // If water fog density has been changed, save it.
+ if (mPrevFogDensity != mFogDensity)
+ {
+ gSavedSettings.setF32("WaterFogDensity", mFogDensity);
+ mPrevFogDensity = mFogDensity;
+ }
+
// sync menus if they exist
LLFloaterWater* waterfloater = LLFloaterReg::findTypedInstance<LLFloaterWater>("env_water");
if(waterfloater)
@@ -449,7 +465,24 @@ LLWaterParamManager * LLWaterParamManager::instance()
sInstance->loadAllPresets(LLStringUtil::null);
sInstance->getParamSet("Default", sInstance->mCurParams);
+ sInstance->initOverrides();
}
return sInstance;
}
+
+void LLWaterParamManager::initOverrides()
+{
+ // Override fog color from the current preset with the saved setting.
+ LLColor4 fog_color_override = gSavedSettings.getColor4("WaterFogColor");
+ mFogColor = fog_color_override;
+ mPrevFogColor = fog_color_override;
+ mCurParams.set("waterFogColor", fog_color_override);
+
+ // Do the same with fog density.
+ F32 fog_density = gSavedSettings.getF32("WaterFogDensity");
+ mPrevFogDensity = fog_density;
+ mFogDensity = fog_density;
+ mCurParams.set("waterFogDensity", fog_density);
+ setDensitySliderValue(mFogDensity.mExp);
+}
diff --git a/indra/newview/llwaterparammanager.h b/indra/newview/llwaterparammanager.h
index c479f1861c..f465034c39 100644
--- a/indra/newview/llwaterparammanager.h
+++ b/indra/newview/llwaterparammanager.h
@@ -284,6 +284,9 @@ public:
// singleton pattern implementation
static LLWaterParamManager * instance();
+private:
+ void initOverrides();
+
public:
LLWaterParamSet mCurParams;
@@ -314,6 +317,9 @@ private:
LLVector4 mWaterPlane;
F32 mWaterFogKS;
+ LLColor4 mPrevFogColor;
+ F32 mPrevFogDensity;
+
// our parameter manager singleton instance
static LLWaterParamManager * sInstance;
};
diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp
index f933be4d8f..9e95604712 100644
--- a/indra/newview/llwearabletype.cpp
+++ b/indra/newview/llwearabletype.cpp
@@ -144,6 +144,7 @@ BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
+ if (!entry) return FALSE;
return entry->mDisableCameraSwitch;
}
@@ -152,6 +153,7 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
+ if (!entry) return FALSE;
return entry->mAllowMultiwear;
}
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 96bc8cbdd9..2d67786c01 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1,1348 +1,1333 @@
-/**
- * @file llworld.cpp
- * @brief Initial test structure to organize viewer regions
- *
- * $LicenseInfo:firstyear=2001&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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llworld.h"
-#include "llrender.h"
-
-#include "indra_constants.h"
-#include "llstl.h"
-
-#include "llagent.h"
-#include "llviewercontrol.h"
-#include "lldrawpool.h"
-#include "llglheaders.h"
-#include "llhttpnode.h"
-#include "llregionhandle.h"
-#include "llsurface.h"
-#include "lltrans.h"
-#include "llviewercamera.h"
-#include "llviewertexture.h"
-#include "llviewertexturelist.h"
-#include "llviewernetwork.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparceloverlay.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llvlcomposition.h"
-#include "llvoavatar.h"
-#include "llvowater.h"
-#include "message.h"
-#include "pipeline.h"
-#include "llappviewer.h" // for do_disconnect()
-
-#include <deque>
-#include <queue>
-#include <map>
-#include <cstring>
-
-//
-// Globals
-//
-U32 gAgentPauseSerialNum = 0;
-
-//
-// Constants
-//
-const S32 MAX_NUMBER_OF_CLOUDS = 750;
-const S32 WORLD_PATCH_SIZE = 16;
-
-extern LLColor4U MAX_WATER_COLOR;
-
-const U32 LLWorld::mWidth = 256;
-
-// meters/point, therefore mWidth * mScale = meters per edge
-const F32 LLWorld::mScale = 1.f;
-
-const F32 LLWorld::mWidthInMeters = mWidth * mScale;
-
-//
-// Functions
-//
-
-// allocate the stack
-LLWorld::LLWorld() :
- mLandFarClip(DEFAULT_FAR_PLANE),
- mLastPacketsIn(0),
- mLastPacketsOut(0),
- mLastPacketsLost(0),
- mSpaceTimeUSec(0),
- mClassicCloudsEnabled(TRUE)
-{
- for (S32 i = 0; i < 8; i++)
- {
- mEdgeWaterObjects[i] = NULL;
- }
-
- if (gNoRender)
- {
- return;
- }
-
- LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,4);
- U8 *default_texture = raw->getData();
- *(default_texture++) = MAX_WATER_COLOR.mV[0];
- *(default_texture++) = MAX_WATER_COLOR.mV[1];
- *(default_texture++) = MAX_WATER_COLOR.mV[2];
- *(default_texture++) = MAX_WATER_COLOR.mV[3];
-
- mDefaultWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
- gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
- mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
-
-}
-
-
-void LLWorld::destroyClass()
-{
- mHoleWaterObjects.clear();
- gObjectList.destroy();
- for(region_list_t::iterator region_it = mRegionList.begin(); region_it != mRegionList.end(); )
- {
- LLViewerRegion* region_to_delete = *region_it++;
- removeRegion(region_to_delete->getHost());
- }
- if(LLVOCache::hasInstance())
- {
- LLVOCache::getInstance()->destroyClass() ;
- }
- LLViewerPartSim::getInstance()->destroyClass();
-}
-
-
-LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
-{
- LLMemType mt(LLMemType::MTYPE_REGIONS);
- llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
- LLViewerRegion *regionp = getRegionFromHandle(region_handle);
- if (regionp)
- {
- llinfos << "Region exists, removing it " << llendl;
- LLHost old_host = regionp->getHost();
- // region already exists!
- if (host == old_host && regionp->isAlive())
- {
- // This is a duplicate for the same host and it's alive, don't bother.
- return regionp;
- }
-
- if (host != old_host)
- {
- llwarns << "LLWorld::addRegion exists, but old host " << old_host
- << " does not match new host " << host << llendl;
- }
- if (!regionp->isAlive())
- {
- llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl;
- }
-
- // Kill the old host, and then we can continue on and add the new host. We have to kill even if the host
- // matches, because all the agent state for the new camera is completely different.
- removeRegion(old_host);
- }
-
- U32 iindex = 0;
- U32 jindex = 0;
- from_region_handle(region_handle, &iindex, &jindex);
- S32 x = (S32)(iindex/mWidth);
- S32 y = (S32)(jindex/mWidth);
- llinfos << "Adding new region (" << x << ":" << y << ")" << llendl;
- llinfos << "Host: " << host << llendl;
-
- LLVector3d origin_global;
-
- origin_global = from_region_handle(region_handle);
-
- regionp = new LLViewerRegion(region_handle,
- host,
- mWidth,
- WORLD_PATCH_SIZE,
- getRegionWidthInMeters() );
- if (!regionp)
- {
- llerrs << "Unable to create new region!" << llendl;
- }
-
- regionp->mCloudLayer.create(regionp);
- regionp->mCloudLayer.setWidth((F32)mWidth);
- regionp->mCloudLayer.setWindPointer(&regionp->mWind);
-
- mRegionList.push_back(regionp);
- mActiveRegionList.push_back(regionp);
- mCulledRegionList.push_back(regionp);
-
-
- // Find all the adjacent regions, and attach them.
- // Generate handles for all of the adjacent regions, and attach them in the correct way.
- // connect the edges
- F32 adj_x = 0.f;
- F32 adj_y = 0.f;
- F32 region_x = 0.f;
- F32 region_y = 0.f;
- U64 adj_handle = 0;
-
- F32 width = getRegionWidthInMeters();
-
- LLViewerRegion *neighborp;
- from_region_handle(region_handle, &region_x, &region_y);
-
- // Iterate through all directions, and connect neighbors if there.
- S32 dir;
- for (dir = 0; dir < 8; dir++)
- {
- adj_x = region_x + width * gDirAxes[dir][0];
- adj_y = region_y + width * gDirAxes[dir][1];
- to_region_handle(adj_x, adj_y, &adj_handle);
-
- neighborp = getRegionFromHandle(adj_handle);
- if (neighborp)
- {
- //llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
- regionp->connectNeighbor(neighborp, dir);
- }
- }
-
- updateWaterObjects();
-
- return regionp;
-}
-
-
-void LLWorld::removeRegion(const LLHost &host)
-{
- F32 x, y;
-
- LLViewerRegion *regionp = getRegion(host);
- if (!regionp)
- {
- llwarns << "Trying to remove region that doesn't exist!" << llendl;
- return;
- }
-
- if (regionp == gAgent.getRegion())
- {
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* reg = *iter;
- llwarns << "RegionDump: " << reg->getName()
- << " " << reg->getHost()
- << " " << reg->getOriginGlobal()
- << llendl;
- }
-
- llwarns << "Agent position global " << gAgent.getPositionGlobal()
- << " agent " << gAgent.getPositionAgent()
- << llendl;
-
- llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl;
-
- llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl;
-
- llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl;
- LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected"));
-
- regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed.
- return;
- }
-
- from_region_handle(regionp->getHandle(), &x, &y);
- llinfos << "Removing region " << x << ":" << y << llendl;
-
- mRegionList.remove(regionp);
- mActiveRegionList.remove(regionp);
- mCulledRegionList.remove(regionp);
- mVisibleRegionList.remove(regionp);
-
- delete regionp;
-
- updateWaterObjects();
-
- //double check all objects of this region are removed.
- gObjectList.clearAllMapObjectsInRegion(regionp) ;
- //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ;
-}
-
-
-LLViewerRegion* LLWorld::getRegion(const LLHost &host)
-{
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (regionp->getHost() == host)
- {
- return regionp;
- }
- }
- return NULL;
-}
-
-LLViewerRegion* LLWorld::getRegionFromPosAgent(const LLVector3 &pos)
-{
- return getRegionFromPosGlobal(gAgent.getPosGlobalFromAgent(pos));
-}
-
-LLViewerRegion* LLWorld::getRegionFromPosGlobal(const LLVector3d &pos)
-{
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (regionp->pointInRegionGlobal(pos))
- {
- return regionp;
- }
- }
- return NULL;
-}
-
-
-LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos)
-{
- if (positionRegionValidGlobal(end_pos))
- {
- return end_pos;
- }
-
- LLViewerRegion* regionp = getRegionFromPosGlobal(start_pos);
- if (!regionp)
- {
- return start_pos;
- }
-
- LLVector3d delta_pos = end_pos - start_pos;
- LLVector3d delta_pos_abs;
- delta_pos_abs.setVec(delta_pos);
- delta_pos_abs.abs();
-
- LLVector3 region_coord = regionp->getPosRegionFromGlobal(end_pos);
- F64 clip_factor = 1.0;
- F32 region_width = regionp->getWidth();
- if (region_coord.mV[VX] < 0.f)
- {
- if (region_coord.mV[VY] < region_coord.mV[VX])
- {
- // clip along y -
- clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
- }
- else
- {
- // clip along x -
- clip_factor = -(region_coord.mV[VX] / delta_pos_abs.mdV[VX]);
- }
- }
- else if (region_coord.mV[VX] > region_width)
- {
- if (region_coord.mV[VY] > region_coord.mV[VX])
- {
- // clip along y +
- clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
- }
- else
- {
- //clip along x +
- clip_factor = (region_coord.mV[VX] - region_width) / delta_pos_abs.mdV[VX];
- }
- }
- else if (region_coord.mV[VY] < 0.f)
- {
- // clip along y -
- clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
- }
- else if (region_coord.mV[VY] > region_width)
- {
- // clip along y +
- clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
- }
-
- // clamp to within region dimensions
- LLVector3d final_region_pos = LLVector3d(region_coord) - (delta_pos * clip_factor);
- final_region_pos.mdV[VX] = llclamp(final_region_pos.mdV[VX], 0.0,
- (F64)(region_width - F_ALMOST_ZERO));
- final_region_pos.mdV[VY] = llclamp(final_region_pos.mdV[VY], 0.0,
- (F64)(region_width - F_ALMOST_ZERO));
- final_region_pos.mdV[VZ] = llclamp(final_region_pos.mdV[VZ], 0.0,
- (F64)(LLWorld::getInstance()->getRegionMaxHeight() - F_ALMOST_ZERO));
- return regionp->getPosGlobalFromRegion(LLVector3(final_region_pos));
-}
-
-LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
-{
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (regionp->getHandle() == handle)
- {
- return regionp;
- }
- }
- return NULL;
-}
-
-
-void LLWorld::updateAgentOffset(const LLVector3d &offset_global)
-{
-#if 0
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->setAgentOffset(offset_global);
- }
-#endif
-}
-
-
-BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global)
-{
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (regionp->pointInRegionGlobal(pos_global))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-// Allow objects to go up to their radius underground.
-F32 LLWorld::getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos)
-{
- F32 land_height = resolveLandHeightGlobal(global_pos);
- F32 radius = 0.5f * object->getScale().length();
- return land_height - radius;
-}
-
-
-
-LLViewerRegion* LLWorld::resolveRegionGlobal(LLVector3 &pos_region, const LLVector3d &pos_global)
-{
- LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
-
- if (regionp)
- {
- pos_region = regionp->getPosRegionFromGlobal(pos_global);
- return regionp;
- }
-
- return NULL;
-}
-
-
-LLViewerRegion* LLWorld::resolveRegionAgent(LLVector3 &pos_region, const LLVector3 &pos_agent)
-{
- LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
- LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
-
- if (regionp)
- {
- pos_region = regionp->getPosRegionFromGlobal(pos_global);
- return regionp;
- }
-
- return NULL;
-}
-
-
-F32 LLWorld::resolveLandHeightAgent(const LLVector3 &pos_agent)
-{
- LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
- return resolveLandHeightGlobal(pos_global);
-}
-
-
-F32 LLWorld::resolveLandHeightGlobal(const LLVector3d &pos_global)
-{
- LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
- if (regionp)
- {
- return regionp->getLand().resolveHeightGlobal(pos_global);
- }
- return 0.0f;
-}
-
-
-// Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a)
-// point where the the line intersects an object or the land surface. Stores the results
-// in "intersection" and "intersection_normal" and returns a scalar value that represents
-// the normalized distance along the line from "point_a" to "intersection".
-//
-// Currently assumes point_a and point_b only differ in z-direction,
-// but it may eventually become more general.
-F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b,
- LLVector3d &intersection, LLVector3 &intersection_normal,
- LLViewerObject **viewerObjectPtr)
-{
- // initialize return value to null
- if (viewerObjectPtr)
- {
- *viewerObjectPtr = NULL;
- }
-
- LLViewerRegion *regionp = getRegionFromPosGlobal(point_a);
- if (!regionp)
- {
- // We're outside the world
- intersection = 0.5f * (point_a + point_b);
- intersection_normal.setVec(0.0f, 0.0f, 1.0f);
- return 0.5f;
- }
-
- // calculate the length of the segment
- F32 segment_length = (F32)((point_a - point_b).length());
- if (0.0f == segment_length)
- {
- intersection = point_a;
- intersection_normal.setVec(0.0f, 0.0f, 1.0f);
- return segment_length;
- }
-
- // get land height
- // Note: we assume that the line is parallel to z-axis here
- LLVector3d land_intersection = point_a;
- F32 normalized_land_distance;
-
- land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a);
- normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length;
- intersection = land_intersection;
- intersection_normal = resolveLandNormalGlobal(land_intersection);
-
- if (avatarp && !avatarp->mFootPlane.isExactlyClear())
- {
- LLVector3 foot_plane_normal(avatarp->mFootPlane.mV);
- LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a);
- // added 0.05 meters to compensate for error in foot plane reported by Havok
- F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f;
- norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f);
- if (norm_dist_from_plane < normalized_land_distance)
- {
- // collided with object before land
- normalized_land_distance = norm_dist_from_plane;
- intersection = point_a;
- intersection.mdV[VZ] -= norm_dist_from_plane * segment_length;
- intersection_normal = foot_plane_normal;
- }
- else
- {
- intersection = land_intersection;
- intersection_normal = resolveLandNormalGlobal(land_intersection);
- }
- }
-
- return normalized_land_distance;
-}
-
-
-LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global)
-{
- // returns a pointer to the patch at this location
- LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
- if (!regionp)
- {
- return NULL;
- }
-
- return regionp->getLand().resolvePatchGlobal(pos_global);
-}
-
-
-LLVector3 LLWorld::resolveLandNormalGlobal(const LLVector3d &pos_global)
-{
- LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
- if (!regionp)
- {
- return LLVector3::z_axis;
- }
-
- return regionp->getLand().resolveNormalGlobal(pos_global);
-}
-
-
-void LLWorld::updateVisibilities()
-{
- F32 cur_far_clip = LLViewerCamera::getInstance()->getFar();
-
- LLViewerCamera::getInstance()->setFar(mLandFarClip);
-
- F32 diagonal_squared = F_SQRT2 * F_SQRT2 * mWidth * mWidth;
- // Go through the culled list and check for visible regions
- for (region_list_t::iterator iter = mCulledRegionList.begin();
- iter != mCulledRegionList.end(); )
- {
- region_list_t::iterator curiter = iter++;
- LLViewerRegion* regionp = *curiter;
- F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
- F32 radius = 0.5f*(F32) sqrt(height * height + diagonal_squared);
- if (!regionp->getLand().hasZData()
- || LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius))
- {
- mCulledRegionList.erase(curiter);
- mVisibleRegionList.push_back(regionp);
- }
- }
-
- // Update all of the visible regions
- for (region_list_t::iterator iter = mVisibleRegionList.begin();
- iter != mVisibleRegionList.end(); )
- {
- region_list_t::iterator curiter = iter++;
- LLViewerRegion* regionp = *curiter;
- if (!regionp->getLand().hasZData())
- {
- continue;
- }
-
- F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
- F32 radius = 0.5f*(F32) sqrt(height * height + diagonal_squared);
- if (LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius))
- {
- regionp->calculateCameraDistance();
- if (!gNoRender)
- {
- regionp->getLand().updatePatchVisibilities(gAgent);
- }
- }
- else
- {
- mVisibleRegionList.erase(curiter);
- mCulledRegionList.push_back(regionp);
- }
- }
-
- // Sort visible regions
- mVisibleRegionList.sort(LLViewerRegion::CompareDistance());
-
- LLViewerCamera::getInstance()->setFar(cur_far_clip);
-}
-
-void LLWorld::updateRegions(F32 max_update_time)
-{
- LLMemType mt_ur(LLMemType::MTYPE_IDLE_UPDATE_REGIONS);
- LLTimer update_timer;
- BOOL did_one = FALSE;
-
- // Perform idle time updates for the regions (and associated surfaces)
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- F32 max_time = max_update_time - update_timer.getElapsedTimeF32();
- if (did_one && max_time <= 0.f)
- break;
- max_time = llmin(max_time, max_update_time*.1f);
- did_one |= regionp->idleUpdate(max_update_time);
- }
-}
-
-void LLWorld::updateParticles()
-{
- LLViewerPartSim::getInstance()->updateSimulation();
-}
-
-void LLWorld::updateClouds(const F32 dt)
-{
- static LLFastTimer::DeclareTimer ftm("World Clouds");
- LLFastTimer t(ftm);
-
- if ( gSavedSettings.getBOOL("FreezeTime") )
- {
- // don't move clouds in snapshot mode
- return;
- }
-
- if (
- mClassicCloudsEnabled !=
- gSavedSettings.getBOOL("SkyUseClassicClouds") )
- {
- // The classic cloud toggle has been flipped
- // gotta update all of the cloud layers
- mClassicCloudsEnabled =
- gSavedSettings.getBOOL("SkyUseClassicClouds");
-
- if ( !mClassicCloudsEnabled && mActiveRegionList.size() )
- {
- // We've transitioned to having classic clouds disabled
- // reset all cloud layers.
- for (
- region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end();
- ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->mCloudLayer.reset();
- }
-
- return;
- }
- }
- else if ( !mClassicCloudsEnabled ) return;
-
- if (mActiveRegionList.size())
- {
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->mCloudLayer.updatePuffs(dt);
- }
-
- // Reshuffle who owns which puffs
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->mCloudLayer.updatePuffOwnership();
- }
-
- // Add new puffs
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->mCloudLayer.updatePuffCount();
- }
- }
-}
-
-LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff)
-{
- if (mActiveRegionList.size())
- {
- // Update all the cloud puff positions, and timer based stuff
- // such as death decay
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- LLCloudGroup *groupp = regionp->mCloudLayer.findCloudGroup(puff);
- if (groupp)
- {
- return groupp;
- }
- }
- }
- return NULL;
-}
-
-
-void LLWorld::renderPropertyLines()
-{
- S32 region_count = 0;
- S32 vertex_count = 0;
-
- for (region_list_t::iterator iter = mVisibleRegionList.begin();
- iter != mVisibleRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- region_count++;
- vertex_count += regionp->renderPropertyLines();
- }
-}
-
-
-void LLWorld::updateNetStats()
-{
- F32 bits = 0.f;
- U32 packets = 0;
-
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->updateNetStats();
- bits += regionp->mBitStat.getCurrent();
- packets += llfloor( regionp->mPacketsStat.getCurrent() );
- }
-
- S32 packets_in = gMessageSystem->mPacketsIn - mLastPacketsIn;
- S32 packets_out = gMessageSystem->mPacketsOut - mLastPacketsOut;
- S32 packets_lost = gMessageSystem->mDroppedPackets - mLastPacketsLost;
-
- S32 actual_in_bits = gMessageSystem->mPacketRing.getAndResetActualInBits();
- S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits();
- LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f);
- LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f);
- LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
- LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in);
- LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out);
- LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets);
- if (packets_in)
- {
- LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(100.f*((F32)packets_lost/(F32)packets_in));
- }
- else
- {
- LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(0.f);
- }
-
- mLastPacketsIn = gMessageSystem->mPacketsIn;
- mLastPacketsOut = gMessageSystem->mPacketsOut;
- mLastPacketsLost = gMessageSystem->mDroppedPackets;
-}
-
-
-void LLWorld::printPacketsLost()
-{
- llinfos << "Simulators:" << llendl;
- llinfos << "----------" << llendl;
-
- LLCircuitData *cdp = NULL;
- for (region_list_t::iterator iter = mActiveRegionList.begin();
- iter != mActiveRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost());
- if (cdp)
- {
- LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal();
-
- llinfos << regionp->getHost() << ", range: " << range.length()
- << " packets lost: " << cdp->getPacketsLost() << llendl;
- }
- }
-}
-
-void LLWorld::processCoarseUpdate(LLMessageSystem* msg, void** user_data)
-{
- LLViewerRegion* region = LLWorld::getInstance()->getRegion(msg->getSender());
- if( region )
- {
- region->updateCoarseLocations(msg);
- }
-}
-
-F32 LLWorld::getLandFarClip() const
-{
- return mLandFarClip;
-}
-
-void LLWorld::setLandFarClip(const F32 far_clip)
-{
- static S32 const rwidth = (S32)REGION_WIDTH_U32;
- S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
- S32 const n2 = (llceil(far_clip) - 1) / rwidth;
- bool need_water_objects_update = n1 != n2;
-
- mLandFarClip = far_clip;
-
- if (need_water_objects_update)
- {
- updateWaterObjects();
- }
-}
-
-// Some region that we're connected to, but not the one we're in, gave us
-// a (possibly) new water height. Update it in our local copy.
-void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height)
-{
- for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
- {
- if ((*iter)->getName() == sim_name)
- {
- (*iter)->setWaterHeight(water_height);
- break;
- }
- }
-}
-
-void LLWorld::updateWaterObjects()
-{
- if (!gAgent.getRegion())
- {
- return;
- }
- if (mRegionList.empty())
- {
- llwarns << "No regions!" << llendl;
- return;
- }
-
- // First, determine the min and max "box" of water objects
- S32 min_x = 0;
- S32 min_y = 0;
- S32 max_x = 0;
- S32 max_y = 0;
- U32 region_x, region_y;
-
- S32 rwidth = 256;
-
- // We only want to fill in water for stuff that's near us, say, within 256 or 512m
- S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256;
-
- LLViewerRegion* regionp = gAgent.getRegion();
- from_region_handle(regionp->getHandle(), &region_x, &region_y);
-
- min_x = (S32)region_x - range;
- min_y = (S32)region_y - range;
- max_x = (S32)region_x + range;
- max_y = (S32)region_y + range;
-
- F32 height = 0.f;
-
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- LLVOWater* waterp = regionp->getLand().getWaterObj();
- height += regionp->getWaterHeight();
- if (waterp)
- {
- gObjectList.updateActive(waterp);
- }
- }
-
- for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
- iter != mHoleWaterObjects.end(); ++ iter)
- {
- LLVOWater* waterp = *iter;
- gObjectList.killObject(waterp);
- }
- mHoleWaterObjects.clear();
-
- // Now, get a list of the holes
- S32 x, y;
- for (x = min_x; x <= max_x; x += rwidth)
- {
- for (y = min_y; y <= max_y; y += rwidth)
- {
- U64 region_handle = to_region_handle(x, y);
- if (!getRegionFromHandle(region_handle))
- {
- LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
- waterp->setUseTexture(FALSE);
- waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
- y + rwidth/2,
- 256.f+DEFAULT_WATER_HEIGHT));
- waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
- gPipeline.createObject(waterp);
- mHoleWaterObjects.push_back(waterp);
- }
- }
- }
-
- // Update edge water objects
- S32 wx, wy;
- S32 center_x, center_y;
- wx = (max_x - min_x) + rwidth;
- wy = (max_y - min_y) + rwidth;
- center_x = min_x + (wx >> 1);
- center_y = min_y + (wy >> 1);
-
- S32 add_boundary[4] = {
- 512 - (max_x - region_x),
- 512 - (max_y - region_y),
- 512 - (region_x - min_x),
- 512 - (region_y - min_y) };
-
- S32 dir;
- for (dir = 0; dir < 8; dir++)
- {
- S32 dim[2] = { 0 };
- switch (gDirAxes[dir][0])
- {
- case -1: dim[0] = add_boundary[2]; break;
- case 0: dim[0] = wx; break;
- default: dim[0] = add_boundary[0]; break;
- }
- switch (gDirAxes[dir][1])
- {
- case -1: dim[1] = add_boundary[3]; break;
- case 0: dim[1] = wy; break;
- default: dim[1] = add_boundary[1]; break;
- }
-
- // Resize and reshape the water objects
- const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]);
- const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]);
-
- LLVOWater* waterp = mEdgeWaterObjects[dir];
- if (!waterp || waterp->isDead())
- {
- // The edge water objects can be dead because they're attached to the region that the
- // agent was in when they were originally created.
- mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER,
- gAgent.getRegion());
- waterp = mEdgeWaterObjects[dir];
- waterp->setUseTexture(FALSE);
- waterp->setIsEdgePatch(TRUE);
- gPipeline.createObject(waterp);
- }
-
- waterp->setRegion(gAgent.getRegion());
- LLVector3d water_pos(water_center_x, water_center_y,
- DEFAULT_WATER_HEIGHT+256.f);
- LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
-
- //stretch out to horizon
- water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]);
- water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]);
-
- water_pos.mdV[0] += 1024.f * gDirAxes[dir][0];
- water_pos.mdV[1] += 1024.f * gDirAxes[dir][1];
-
- waterp->setPositionGlobal(water_pos);
- waterp->setScale(water_scale);
-
- gObjectList.updateActive(waterp);
- }
-}
-
-
-void LLWorld::shiftRegions(const LLVector3& offset)
-{
- for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
- {
- LLViewerRegion* region = *i;
- region->updateRenderMatrix();
- }
-
- LLViewerPartSim::getInstance()->shift(offset);
-}
-
-LLViewerTexture* LLWorld::getDefaultWaterTexture()
-{
- return mDefaultWaterTexturep;
-}
-
-void LLWorld::setSpaceTimeUSec(const U64 space_time_usec)
-{
- mSpaceTimeUSec = space_time_usec;
-}
-
-U64 LLWorld::getSpaceTimeUSec() const
-{
- return mSpaceTimeUSec;
-}
-
-void LLWorld::requestCacheMisses()
-{
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->requestCacheMisses();
- }
-}
-
-void LLWorld::getInfo(LLSD& info)
-{
- LLSD region_info;
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- regionp->getInfo(region_info);
- info["World"].append(region_info);
- }
-}
-
-void LLWorld::disconnectRegions()
-{
- LLMessageSystem* msg = gMessageSystem;
- for (region_list_t::iterator iter = mRegionList.begin();
- iter != mRegionList.end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- if (regionp == gAgent.getRegion())
- {
- // Skip the main agent
- continue;
- }
-
- llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl;
- msg->newMessageFast(_PREHASH_AgentQuitCopy);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_FuseBlock);
- msg->addU32Fast(_PREHASH_ViewerCircuitCode, gMessageSystem->mOurCircuitCode);
- msg->sendMessage(regionp->getHost());
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim");
-
-void process_enable_simulator(LLMessageSystem *msg, void **user_data)
-{
- LLFastTimer t(FTM_ENABLE_SIMULATOR);
- // enable the appropriate circuit for this simulator and
- // add its values into the gSimulator structure
- U64 handle;
- U32 ip_u32;
- U16 port;
-
- msg->getU64Fast(_PREHASH_SimulatorInfo, _PREHASH_Handle, handle);
- msg->getIPAddrFast(_PREHASH_SimulatorInfo, _PREHASH_IP, ip_u32);
- msg->getIPPortFast(_PREHASH_SimulatorInfo, _PREHASH_Port, port);
-
- // which simulator should we modify?
- LLHost sim(ip_u32, port);
-
- // Viewer trusts the simulator.
- msg->enableCircuit(sim, TRUE);
- LLWorld::getInstance()->addRegion(handle, sim);
-
- // give the simulator a message it can use to get ip and port
- llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl;
- msg->newMessageFast(_PREHASH_UseCircuitCode);
- msg->nextBlockFast(_PREHASH_CircuitCode);
- msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
- msg->sendReliable(sim);
-}
-
-class LLEstablishAgentCommunication : public LLHTTPNode
-{
- LOG_CLASS(LLEstablishAgentCommunication);
-public:
- virtual void describe(Description& desc) const
- {
- desc.shortInfo("seed capability info for a region");
- desc.postAPI();
- desc.input(
- "{ seed-capability: ..., sim-ip: ..., sim-port }");
- desc.source(__FILE__, __LINE__);
- }
-
- virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
- {
- if (!input["body"].has("agent-id") ||
- !input["body"].has("sim-ip-and-port") ||
- !input["body"].has("seed-capability"))
- {
- llwarns << "invalid parameters" << llendl;
- return;
- }
-
- LLHost sim(input["body"]["sim-ip-and-port"].asString());
-
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim);
- if (!regionp)
- {
- llwarns << "Got EstablishAgentCommunication for unknown region "
- << sim << llendl;
- return;
- }
- regionp->setSeedCapability(input["body"]["seed-capability"]);
- }
-};
-
-// disable the circuit to this simulator
-// Called in response to "DisableSimulator" message.
-void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
-{
- LLHost host = mesgsys->getSender();
-
- //llinfos << "Disabling simulator with message from " << host << llendl;
- LLWorld::getInstance()->removeRegion(host);
-
- mesgsys->disableCircuit(host);
-}
-
-
-void process_region_handshake(LLMessageSystem* msg, void** user_data)
-{
- LLHost host = msg->getSender();
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(host);
- if (!regionp)
- {
- llwarns << "Got region handshake for unknown region "
- << host << llendl;
- return;
- }
-
- regionp->unpackRegionHandshake();
-}
-
-
-void send_agent_pause()
-{
- // *NOTE:Mani Pausing the mainloop timeout. Otherwise a long modal event may cause
- // the thread monitor to timeout.
- LLAppViewer::instance()->pauseMainloopTimeout();
-
- // Note: used to check for LLWorld initialization before it became a singleton.
- // Rather than just remove this check I'm changing it to assure that the message
- // system has been initialized. -MG
- if (!gMessageSystem)
- {
- return;
- }
-
- gMessageSystem->newMessageFast(_PREHASH_AgentPause);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
-
- gAgentPauseSerialNum++;
- gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- gMessageSystem->sendReliable(regionp->getHost());
- }
-
- gObjectList.mWasPaused = TRUE;
-}
-
-
-void send_agent_resume()
-{
- // Note: used to check for LLWorld initialization before it became a singleton.
- // Rather than just remove this check I'm changing it to assure that the message
- // system has been initialized. -MG
- if (!gMessageSystem)
- {
- return;
- }
-
- gMessageSystem->newMessageFast(_PREHASH_AgentResume);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
-
- gAgentPauseSerialNum++;
- gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
-
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- gMessageSystem->sendReliable(regionp->getHost());
- }
-
- // Reset the FPS counter to avoid an invalid fps
- LLViewerStats::getInstance()->mFPSStat.start();
-
- LLAppViewer::instance()->resumeMainloopTimeout();
-}
-
-static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin)
-{
- LLVector3d pos_global;
- LLVector3 pos_local;
- U8 bits;
-
- bits = compact_local & 0xFF;
- pos_local.mV[VZ] = F32(bits) * 4.f;
- compact_local >>= 8;
-
- bits = compact_local & 0xFF;
- pos_local.mV[VY] = (F32)bits;
- compact_local >>= 8;
-
- bits = compact_local & 0xFF;
- pos_local.mV[VX] = (F32)bits;
-
- pos_global.setVec( pos_local );
- pos_global += region_origin;
- return pos_global;
-}
-
-void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positions, const LLVector3d& relative_to, F32 radius) const
-{
- if(avatar_ids != NULL)
- {
- avatar_ids->clear();
- }
- if(positions != NULL)
- {
- positions->clear();
- }
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* regionp = *iter;
- const LLVector3d& origin_global = regionp->getOriginGlobal();
- S32 count = regionp->mMapAvatars.count();
- for (S32 i = 0; i < count; i++)
- {
- LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.get(i), origin_global);
- if(dist_vec(pos_global, relative_to) <= radius)
- {
- if(positions != NULL)
- {
- positions->push_back(pos_global);
- }
- if(avatar_ids != NULL)
- {
- avatar_ids->push_back(regionp->mMapAvatarIDs.get(i));
- }
- }
- }
- }
- // retrieve the list of close avatars from viewer objects as well
- // for when we are above 1000m, only do this when we are retrieving
- // uuid's too as there could be duplicates
- if(avatar_ids != NULL)
- {
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
- {
- LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter;
- if(pVOAvatar->isDead() || pVOAvatar->isSelf())
- continue;
- LLUUID uuid = pVOAvatar->getID();
- if(uuid.isNull())
- continue;
- LLVector3d pos_global = pVOAvatar->getPositionGlobal();
- if(dist_vec(pos_global, relative_to) <= radius)
- {
- bool found = false;
- uuid_vec_t::iterator sel_iter = avatar_ids->begin();
- for (; sel_iter != avatar_ids->end(); sel_iter++)
- {
- if(*sel_iter == uuid)
- {
- found = true;
- break;
- }
- }
- if(!found)
- {
- if(positions != NULL)
- positions->push_back(pos_global);
- avatar_ids->push_back(uuid);
- }
- }
- }
- }
-}
-
-
-LLHTTPRegistration<LLEstablishAgentCommunication>
- gHTTPRegistrationEstablishAgentCommunication(
- "/message/EstablishAgentCommunication");
+/**
+ * @file llworld.cpp
+ * @brief Initial test structure to organize viewer regions
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llworld.h"
+#include "llrender.h"
+
+#include "indra_constants.h"
+#include "llstl.h"
+
+#include "llagent.h"
+#include "llviewercontrol.h"
+#include "lldrawpool.h"
+#include "llglheaders.h"
+#include "llhttpnode.h"
+#include "llregionhandle.h"
+#include "llsurface.h"
+#include "lltrans.h"
+#include "llviewercamera.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparceloverlay.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llvlcomposition.h"
+#include "llvoavatar.h"
+#include "llvowater.h"
+#include "message.h"
+#include "pipeline.h"
+#include "llappviewer.h" // for do_disconnect()
+
+#include <deque>
+#include <queue>
+#include <map>
+#include <cstring>
+
+//
+// Globals
+//
+U32 gAgentPauseSerialNum = 0;
+
+//
+// Constants
+//
+const S32 MAX_NUMBER_OF_CLOUDS = 750;
+const S32 WORLD_PATCH_SIZE = 16;
+
+extern LLColor4U MAX_WATER_COLOR;
+
+const U32 LLWorld::mWidth = 256;
+
+// meters/point, therefore mWidth * mScale = meters per edge
+const F32 LLWorld::mScale = 1.f;
+
+const F32 LLWorld::mWidthInMeters = mWidth * mScale;
+
+//
+// Functions
+//
+
+// allocate the stack
+LLWorld::LLWorld() :
+ mLandFarClip(DEFAULT_FAR_PLANE),
+ mLastPacketsIn(0),
+ mLastPacketsOut(0),
+ mLastPacketsLost(0),
+ mSpaceTimeUSec(0),
+ mClassicCloudsEnabled(TRUE)
+{
+ for (S32 i = 0; i < 8; i++)
+ {
+ mEdgeWaterObjects[i] = NULL;
+ }
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,4);
+ U8 *default_texture = raw->getData();
+ *(default_texture++) = MAX_WATER_COLOR.mV[0];
+ *(default_texture++) = MAX_WATER_COLOR.mV[1];
+ *(default_texture++) = MAX_WATER_COLOR.mV[2];
+ *(default_texture++) = MAX_WATER_COLOR.mV[3];
+
+ mDefaultWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
+ gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
+ mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+}
+
+
+void LLWorld::destroyClass()
+{
+ mHoleWaterObjects.clear();
+ gObjectList.destroy();
+ for(region_list_t::iterator region_it = mRegionList.begin(); region_it != mRegionList.end(); )
+ {
+ LLViewerRegion* region_to_delete = *region_it++;
+ removeRegion(region_to_delete->getHost());
+ }
+ if(LLVOCache::hasInstance())
+ {
+ LLVOCache::getInstance()->destroyClass() ;
+ }
+ LLViewerPartSim::getInstance()->destroyClass();
+}
+
+
+LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
+{
+ LLMemType mt(LLMemType::MTYPE_REGIONS);
+ llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl;
+ LLViewerRegion *regionp = getRegionFromHandle(region_handle);
+ if (regionp)
+ {
+ llinfos << "Region exists, removing it " << llendl;
+ LLHost old_host = regionp->getHost();
+ // region already exists!
+ if (host == old_host && regionp->isAlive())
+ {
+ // This is a duplicate for the same host and it's alive, don't bother.
+ return regionp;
+ }
+
+ if (host != old_host)
+ {
+ llwarns << "LLWorld::addRegion exists, but old host " << old_host
+ << " does not match new host " << host << llendl;
+ }
+ if (!regionp->isAlive())
+ {
+ llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl;
+ }
+
+ // Kill the old host, and then we can continue on and add the new host. We have to kill even if the host
+ // matches, because all the agent state for the new camera is completely different.
+ removeRegion(old_host);
+ }
+
+ U32 iindex = 0;
+ U32 jindex = 0;
+ from_region_handle(region_handle, &iindex, &jindex);
+ S32 x = (S32)(iindex/mWidth);
+ S32 y = (S32)(jindex/mWidth);
+ llinfos << "Adding new region (" << x << ":" << y << ")" << llendl;
+ llinfos << "Host: " << host << llendl;
+
+ LLVector3d origin_global;
+
+ origin_global = from_region_handle(region_handle);
+
+ regionp = new LLViewerRegion(region_handle,
+ host,
+ mWidth,
+ WORLD_PATCH_SIZE,
+ getRegionWidthInMeters() );
+ if (!regionp)
+ {
+ llerrs << "Unable to create new region!" << llendl;
+ }
+
+ regionp->mCloudLayer.create(regionp);
+ regionp->mCloudLayer.setWidth((F32)mWidth);
+ regionp->mCloudLayer.setWindPointer(&regionp->mWind);
+
+ mRegionList.push_back(regionp);
+ mActiveRegionList.push_back(regionp);
+ mCulledRegionList.push_back(regionp);
+
+
+ // Find all the adjacent regions, and attach them.
+ // Generate handles for all of the adjacent regions, and attach them in the correct way.
+ // connect the edges
+ F32 adj_x = 0.f;
+ F32 adj_y = 0.f;
+ F32 region_x = 0.f;
+ F32 region_y = 0.f;
+ U64 adj_handle = 0;
+
+ F32 width = getRegionWidthInMeters();
+
+ LLViewerRegion *neighborp;
+ from_region_handle(region_handle, &region_x, &region_y);
+
+ // Iterate through all directions, and connect neighbors if there.
+ S32 dir;
+ for (dir = 0; dir < 8; dir++)
+ {
+ adj_x = region_x + width * gDirAxes[dir][0];
+ adj_y = region_y + width * gDirAxes[dir][1];
+ to_region_handle(adj_x, adj_y, &adj_handle);
+
+ neighborp = getRegionFromHandle(adj_handle);
+ if (neighborp)
+ {
+ //llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl;
+ regionp->connectNeighbor(neighborp, dir);
+ }
+ }
+
+ updateWaterObjects();
+
+ return regionp;
+}
+
+
+void LLWorld::removeRegion(const LLHost &host)
+{
+ F32 x, y;
+
+ LLViewerRegion *regionp = getRegion(host);
+ if (!regionp)
+ {
+ llwarns << "Trying to remove region that doesn't exist!" << llendl;
+ return;
+ }
+
+ if (regionp == gAgent.getRegion())
+ {
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* reg = *iter;
+ llwarns << "RegionDump: " << reg->getName()
+ << " " << reg->getHost()
+ << " " << reg->getOriginGlobal()
+ << llendl;
+ }
+
+ llwarns << "Agent position global " << gAgent.getPositionGlobal()
+ << " agent " << gAgent.getPositionAgent()
+ << llendl;
+
+ llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl;
+
+ llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl;
+
+ llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl;
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected"));
+
+ regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed.
+ return;
+ }
+
+ from_region_handle(regionp->getHandle(), &x, &y);
+ llinfos << "Removing region " << x << ":" << y << llendl;
+
+ mRegionList.remove(regionp);
+ mActiveRegionList.remove(regionp);
+ mCulledRegionList.remove(regionp);
+ mVisibleRegionList.remove(regionp);
+
+ delete regionp;
+
+ updateWaterObjects();
+
+ //double check all objects of this region are removed.
+ gObjectList.clearAllMapObjectsInRegion(regionp) ;
+ //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ;
+}
+
+
+LLViewerRegion* LLWorld::getRegion(const LLHost &host)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->getHost() == host)
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+LLViewerRegion* LLWorld::getRegionFromPosAgent(const LLVector3 &pos)
+{
+ return getRegionFromPosGlobal(gAgent.getPosGlobalFromAgent(pos));
+}
+
+LLViewerRegion* LLWorld::getRegionFromPosGlobal(const LLVector3d &pos)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->pointInRegionGlobal(pos))
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+
+LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos)
+{
+ if (positionRegionValidGlobal(end_pos))
+ {
+ return end_pos;
+ }
+
+ LLViewerRegion* regionp = getRegionFromPosGlobal(start_pos);
+ if (!regionp)
+ {
+ return start_pos;
+ }
+
+ LLVector3d delta_pos = end_pos - start_pos;
+ LLVector3d delta_pos_abs;
+ delta_pos_abs.setVec(delta_pos);
+ delta_pos_abs.abs();
+
+ LLVector3 region_coord = regionp->getPosRegionFromGlobal(end_pos);
+ F64 clip_factor = 1.0;
+ F32 region_width = regionp->getWidth();
+ if (region_coord.mV[VX] < 0.f)
+ {
+ if (region_coord.mV[VY] < region_coord.mV[VX])
+ {
+ // clip along y -
+ clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
+ }
+ else
+ {
+ // clip along x -
+ clip_factor = -(region_coord.mV[VX] / delta_pos_abs.mdV[VX]);
+ }
+ }
+ else if (region_coord.mV[VX] > region_width)
+ {
+ if (region_coord.mV[VY] > region_coord.mV[VX])
+ {
+ // clip along y +
+ clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
+ }
+ else
+ {
+ //clip along x +
+ clip_factor = (region_coord.mV[VX] - region_width) / delta_pos_abs.mdV[VX];
+ }
+ }
+ else if (region_coord.mV[VY] < 0.f)
+ {
+ // clip along y -
+ clip_factor = -(region_coord.mV[VY] / delta_pos_abs.mdV[VY]);
+ }
+ else if (region_coord.mV[VY] > region_width)
+ {
+ // clip along y +
+ clip_factor = (region_coord.mV[VY] - region_width) / delta_pos_abs.mdV[VY];
+ }
+
+ // clamp to within region dimensions
+ LLVector3d final_region_pos = LLVector3d(region_coord) - (delta_pos * clip_factor);
+ final_region_pos.mdV[VX] = llclamp(final_region_pos.mdV[VX], 0.0,
+ (F64)(region_width - F_ALMOST_ZERO));
+ final_region_pos.mdV[VY] = llclamp(final_region_pos.mdV[VY], 0.0,
+ (F64)(region_width - F_ALMOST_ZERO));
+ final_region_pos.mdV[VZ] = llclamp(final_region_pos.mdV[VZ], 0.0,
+ (F64)(LLWorld::getInstance()->getRegionMaxHeight() - F_ALMOST_ZERO));
+ return regionp->getPosGlobalFromRegion(LLVector3(final_region_pos));
+}
+
+LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->getHandle() == handle)
+ {
+ return regionp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLWorld::updateAgentOffset(const LLVector3d &offset_global)
+{
+#if 0
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->setAgentOffset(offset_global);
+ }
+#endif
+}
+
+
+BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global)
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp->pointInRegionGlobal(pos_global))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+// Allow objects to go up to their radius underground.
+F32 LLWorld::getMinAllowedZ(LLViewerObject* object, const LLVector3d &global_pos)
+{
+ F32 land_height = resolveLandHeightGlobal(global_pos);
+ F32 radius = 0.5f * object->getScale().length();
+ return land_height - radius;
+}
+
+
+
+LLViewerRegion* LLWorld::resolveRegionGlobal(LLVector3 &pos_region, const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+
+ if (regionp)
+ {
+ pos_region = regionp->getPosRegionFromGlobal(pos_global);
+ return regionp;
+ }
+
+ return NULL;
+}
+
+
+LLViewerRegion* LLWorld::resolveRegionAgent(LLVector3 &pos_region, const LLVector3 &pos_agent)
+{
+ LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+
+ if (regionp)
+ {
+ pos_region = regionp->getPosRegionFromGlobal(pos_global);
+ return regionp;
+ }
+
+ return NULL;
+}
+
+
+F32 LLWorld::resolveLandHeightAgent(const LLVector3 &pos_agent)
+{
+ LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent);
+ return resolveLandHeightGlobal(pos_global);
+}
+
+
+F32 LLWorld::resolveLandHeightGlobal(const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (regionp)
+ {
+ return regionp->getLand().resolveHeightGlobal(pos_global);
+ }
+ return 0.0f;
+}
+
+
+// Takes a line defined by "point_a" and "point_b" and determines the closest (to point_a)
+// point where the the line intersects an object or the land surface. Stores the results
+// in "intersection" and "intersection_normal" and returns a scalar value that represents
+// the normalized distance along the line from "point_a" to "intersection".
+//
+// Currently assumes point_a and point_b only differ in z-direction,
+// but it may eventually become more general.
+F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d &point_a, const LLVector3d &point_b,
+ LLVector3d &intersection, LLVector3 &intersection_normal,
+ LLViewerObject **viewerObjectPtr)
+{
+ // initialize return value to null
+ if (viewerObjectPtr)
+ {
+ *viewerObjectPtr = NULL;
+ }
+
+ LLViewerRegion *regionp = getRegionFromPosGlobal(point_a);
+ if (!regionp)
+ {
+ // We're outside the world
+ intersection = 0.5f * (point_a + point_b);
+ intersection_normal.setVec(0.0f, 0.0f, 1.0f);
+ return 0.5f;
+ }
+
+ // calculate the length of the segment
+ F32 segment_length = (F32)((point_a - point_b).length());
+ if (0.0f == segment_length)
+ {
+ intersection = point_a;
+ intersection_normal.setVec(0.0f, 0.0f, 1.0f);
+ return segment_length;
+ }
+
+ // get land height
+ // Note: we assume that the line is parallel to z-axis here
+ LLVector3d land_intersection = point_a;
+ F32 normalized_land_distance;
+
+ land_intersection.mdV[VZ] = regionp->getLand().resolveHeightGlobal(point_a);
+ normalized_land_distance = (F32)(point_a.mdV[VZ] - land_intersection.mdV[VZ]) / segment_length;
+ intersection = land_intersection;
+ intersection_normal = resolveLandNormalGlobal(land_intersection);
+
+ if (avatarp && !avatarp->mFootPlane.isExactlyClear())
+ {
+ LLVector3 foot_plane_normal(avatarp->mFootPlane.mV);
+ LLVector3 start_pt = avatarp->getRegion()->getPosRegionFromGlobal(point_a);
+ // added 0.05 meters to compensate for error in foot plane reported by Havok
+ F32 norm_dist_from_plane = ((start_pt * foot_plane_normal) - avatarp->mFootPlane.mV[VW]) + 0.05f;
+ norm_dist_from_plane = llclamp(norm_dist_from_plane / segment_length, 0.f, 1.f);
+ if (norm_dist_from_plane < normalized_land_distance)
+ {
+ // collided with object before land
+ normalized_land_distance = norm_dist_from_plane;
+ intersection = point_a;
+ intersection.mdV[VZ] -= norm_dist_from_plane * segment_length;
+ intersection_normal = foot_plane_normal;
+ }
+ else
+ {
+ intersection = land_intersection;
+ intersection_normal = resolveLandNormalGlobal(land_intersection);
+ }
+ }
+
+ return normalized_land_distance;
+}
+
+
+LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global)
+{
+ // returns a pointer to the patch at this location
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (!regionp)
+ {
+ return NULL;
+ }
+
+ return regionp->getLand().resolvePatchGlobal(pos_global);
+}
+
+
+LLVector3 LLWorld::resolveLandNormalGlobal(const LLVector3d &pos_global)
+{
+ LLViewerRegion *regionp = getRegionFromPosGlobal(pos_global);
+ if (!regionp)
+ {
+ return LLVector3::z_axis;
+ }
+
+ return regionp->getLand().resolveNormalGlobal(pos_global);
+}
+
+
+void LLWorld::updateVisibilities()
+{
+ F32 cur_far_clip = LLViewerCamera::getInstance()->getFar();
+
+ LLViewerCamera::getInstance()->setFar(mLandFarClip);
+
+ F32 diagonal_squared = F_SQRT2 * F_SQRT2 * mWidth * mWidth;
+ // Go through the culled list and check for visible regions
+ for (region_list_t::iterator iter = mCulledRegionList.begin();
+ iter != mCulledRegionList.end(); )
+ {
+ region_list_t::iterator curiter = iter++;
+ LLViewerRegion* regionp = *curiter;
+ F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
+ F32 radius = 0.5f*(F32) sqrt(height * height + diagonal_squared);
+ if (!regionp->getLand().hasZData()
+ || LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius))
+ {
+ mCulledRegionList.erase(curiter);
+ mVisibleRegionList.push_back(regionp);
+ }
+ }
+
+ // Update all of the visible regions
+ for (region_list_t::iterator iter = mVisibleRegionList.begin();
+ iter != mVisibleRegionList.end(); )
+ {
+ region_list_t::iterator curiter = iter++;
+ LLViewerRegion* regionp = *curiter;
+ if (!regionp->getLand().hasZData())
+ {
+ continue;
+ }
+
+ F32 height = regionp->getLand().getMaxZ() - regionp->getLand().getMinZ();
+ F32 radius = 0.5f*(F32) sqrt(height * height + diagonal_squared);
+ if (LLViewerCamera::getInstance()->sphereInFrustum(regionp->getCenterAgent(), radius))
+ {
+ regionp->calculateCameraDistance();
+ regionp->getLand().updatePatchVisibilities(gAgent);
+ }
+ else
+ {
+ mVisibleRegionList.erase(curiter);
+ mCulledRegionList.push_back(regionp);
+ }
+ }
+
+ // Sort visible regions
+ mVisibleRegionList.sort(LLViewerRegion::CompareDistance());
+
+ LLViewerCamera::getInstance()->setFar(cur_far_clip);
+}
+
+void LLWorld::updateRegions(F32 max_update_time)
+{
+ LLMemType mt_ur(LLMemType::MTYPE_IDLE_UPDATE_REGIONS);
+ LLTimer update_timer;
+ BOOL did_one = FALSE;
+
+ // Perform idle time updates for the regions (and associated surfaces)
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ F32 max_time = max_update_time - update_timer.getElapsedTimeF32();
+ if (did_one && max_time <= 0.f)
+ break;
+ max_time = llmin(max_time, max_update_time*.1f);
+ did_one |= regionp->idleUpdate(max_update_time);
+ }
+}
+
+void LLWorld::updateParticles()
+{
+ LLViewerPartSim::getInstance()->updateSimulation();
+}
+
+void LLWorld::updateClouds(const F32 dt)
+{
+ static LLFastTimer::DeclareTimer ftm("World Clouds");
+ LLFastTimer t(ftm);
+
+ if ( gSavedSettings.getBOOL("FreezeTime") )
+ {
+ // don't move clouds in snapshot mode
+ return;
+ }
+
+ if (
+ mClassicCloudsEnabled !=
+ gSavedSettings.getBOOL("SkyUseClassicClouds") )
+ {
+ // The classic cloud toggle has been flipped
+ // gotta update all of the cloud layers
+ mClassicCloudsEnabled =
+ gSavedSettings.getBOOL("SkyUseClassicClouds");
+
+ if ( !mClassicCloudsEnabled && mActiveRegionList.size() )
+ {
+ // We've transitioned to having classic clouds disabled
+ // reset all cloud layers.
+ for (
+ region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end();
+ ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->mCloudLayer.reset();
+ }
+
+ return;
+ }
+ }
+ else if ( !mClassicCloudsEnabled ) return;
+
+ if (mActiveRegionList.size())
+ {
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->mCloudLayer.updatePuffs(dt);
+ }
+
+ // Reshuffle who owns which puffs
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->mCloudLayer.updatePuffOwnership();
+ }
+
+ // Add new puffs
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->mCloudLayer.updatePuffCount();
+ }
+ }
+}
+
+LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff)
+{
+ if (mActiveRegionList.size())
+ {
+ // Update all the cloud puff positions, and timer based stuff
+ // such as death decay
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ LLCloudGroup *groupp = regionp->mCloudLayer.findCloudGroup(puff);
+ if (groupp)
+ {
+ return groupp;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+void LLWorld::renderPropertyLines()
+{
+ S32 region_count = 0;
+ S32 vertex_count = 0;
+
+ for (region_list_t::iterator iter = mVisibleRegionList.begin();
+ iter != mVisibleRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ region_count++;
+ vertex_count += regionp->renderPropertyLines();
+ }
+}
+
+
+void LLWorld::updateNetStats()
+{
+ F32 bits = 0.f;
+ U32 packets = 0;
+
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->updateNetStats();
+ bits += regionp->mBitStat.getCurrent();
+ packets += llfloor( regionp->mPacketsStat.getCurrent() );
+ }
+
+ S32 packets_in = gMessageSystem->mPacketsIn - mLastPacketsIn;
+ S32 packets_out = gMessageSystem->mPacketsOut - mLastPacketsOut;
+ S32 packets_lost = gMessageSystem->mDroppedPackets - mLastPacketsLost;
+
+ S32 actual_in_bits = gMessageSystem->mPacketRing.getAndResetActualInBits();
+ S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits();
+ LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f);
+ LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f);
+ LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
+ LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in);
+ LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out);
+ LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets);
+ if (packets_in)
+ {
+ LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(100.f*((F32)packets_lost/(F32)packets_in));
+ }
+ else
+ {
+ LLViewerStats::getInstance()->mPacketsLostPercentStat.addValue(0.f);
+ }
+
+ mLastPacketsIn = gMessageSystem->mPacketsIn;
+ mLastPacketsOut = gMessageSystem->mPacketsOut;
+ mLastPacketsLost = gMessageSystem->mDroppedPackets;
+}
+
+
+void LLWorld::printPacketsLost()
+{
+ llinfos << "Simulators:" << llendl;
+ llinfos << "----------" << llendl;
+
+ LLCircuitData *cdp = NULL;
+ for (region_list_t::iterator iter = mActiveRegionList.begin();
+ iter != mActiveRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost());
+ if (cdp)
+ {
+ LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal();
+
+ llinfos << regionp->getHost() << ", range: " << range.length()
+ << " packets lost: " << cdp->getPacketsLost() << llendl;
+ }
+ }
+}
+
+void LLWorld::processCoarseUpdate(LLMessageSystem* msg, void** user_data)
+{
+ LLViewerRegion* region = LLWorld::getInstance()->getRegion(msg->getSender());
+ if( region )
+ {
+ region->updateCoarseLocations(msg);
+ }
+}
+
+F32 LLWorld::getLandFarClip() const
+{
+ return mLandFarClip;
+}
+
+void LLWorld::setLandFarClip(const F32 far_clip)
+{
+ static S32 const rwidth = (S32)REGION_WIDTH_U32;
+ S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
+ S32 const n2 = (llceil(far_clip) - 1) / rwidth;
+ bool need_water_objects_update = n1 != n2;
+
+ mLandFarClip = far_clip;
+
+ if (need_water_objects_update)
+ {
+ updateWaterObjects();
+ }
+}
+
+// Some region that we're connected to, but not the one we're in, gave us
+// a (possibly) new water height. Update it in our local copy.
+void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height)
+{
+ for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter)
+ {
+ if ((*iter)->getName() == sim_name)
+ {
+ (*iter)->setWaterHeight(water_height);
+ break;
+ }
+ }
+}
+
+void LLWorld::updateWaterObjects()
+{
+ if (!gAgent.getRegion())
+ {
+ return;
+ }
+ if (mRegionList.empty())
+ {
+ llwarns << "No regions!" << llendl;
+ return;
+ }
+
+ // First, determine the min and max "box" of water objects
+ S32 min_x = 0;
+ S32 min_y = 0;
+ S32 max_x = 0;
+ S32 max_y = 0;
+ U32 region_x, region_y;
+
+ S32 rwidth = 256;
+
+ // We only want to fill in water for stuff that's near us, say, within 256 or 512m
+ S32 range = LLViewerCamera::getInstance()->getFar() > 256.f ? 512 : 256;
+
+ LLViewerRegion* regionp = gAgent.getRegion();
+ from_region_handle(regionp->getHandle(), &region_x, &region_y);
+
+ min_x = (S32)region_x - range;
+ min_y = (S32)region_y - range;
+ max_x = (S32)region_x + range;
+ max_y = (S32)region_y + range;
+
+ F32 height = 0.f;
+
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ LLVOWater* waterp = regionp->getLand().getWaterObj();
+ height += regionp->getWaterHeight();
+ if (waterp)
+ {
+ gObjectList.updateActive(waterp);
+ }
+ }
+
+ for (std::list<LLVOWater*>::iterator iter = mHoleWaterObjects.begin();
+ iter != mHoleWaterObjects.end(); ++ iter)
+ {
+ LLVOWater* waterp = *iter;
+ gObjectList.killObject(waterp);
+ }
+ mHoleWaterObjects.clear();
+
+ // Now, get a list of the holes
+ S32 x, y;
+ for (x = min_x; x <= max_x; x += rwidth)
+ {
+ for (y = min_y; y <= max_y; y += rwidth)
+ {
+ U64 region_handle = to_region_handle(x, y);
+ if (!getRegionFromHandle(region_handle))
+ {
+ LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
+ waterp->setUseTexture(FALSE);
+ waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
+ y + rwidth/2,
+ 256.f+DEFAULT_WATER_HEIGHT));
+ waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
+ gPipeline.createObject(waterp);
+ mHoleWaterObjects.push_back(waterp);
+ }
+ }
+ }
+
+ // Update edge water objects
+ S32 wx, wy;
+ S32 center_x, center_y;
+ wx = (max_x - min_x) + rwidth;
+ wy = (max_y - min_y) + rwidth;
+ center_x = min_x + (wx >> 1);
+ center_y = min_y + (wy >> 1);
+
+ S32 add_boundary[4] = {
+ 512 - (max_x - region_x),
+ 512 - (max_y - region_y),
+ 512 - (region_x - min_x),
+ 512 - (region_y - min_y) };
+
+ S32 dir;
+ for (dir = 0; dir < 8; dir++)
+ {
+ S32 dim[2] = { 0 };
+ switch (gDirAxes[dir][0])
+ {
+ case -1: dim[0] = add_boundary[2]; break;
+ case 0: dim[0] = wx; break;
+ default: dim[0] = add_boundary[0]; break;
+ }
+ switch (gDirAxes[dir][1])
+ {
+ case -1: dim[1] = add_boundary[3]; break;
+ case 0: dim[1] = wy; break;
+ default: dim[1] = add_boundary[1]; break;
+ }
+
+ // Resize and reshape the water objects
+ const S32 water_center_x = center_x + llround((wx + dim[0]) * 0.5f * gDirAxes[dir][0]);
+ const S32 water_center_y = center_y + llround((wy + dim[1]) * 0.5f * gDirAxes[dir][1]);
+
+ LLVOWater* waterp = mEdgeWaterObjects[dir];
+ if (!waterp || waterp->isDead())
+ {
+ // The edge water objects can be dead because they're attached to the region that the
+ // agent was in when they were originally created.
+ mEdgeWaterObjects[dir] = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER,
+ gAgent.getRegion());
+ waterp = mEdgeWaterObjects[dir];
+ waterp->setUseTexture(FALSE);
+ waterp->setIsEdgePatch(TRUE);
+ gPipeline.createObject(waterp);
+ }
+
+ waterp->setRegion(gAgent.getRegion());
+ LLVector3d water_pos(water_center_x, water_center_y,
+ DEFAULT_WATER_HEIGHT+256.f);
+ LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
+
+ //stretch out to horizon
+ water_scale.mV[0] += fabsf(2048.f * gDirAxes[dir][0]);
+ water_scale.mV[1] += fabsf(2048.f * gDirAxes[dir][1]);
+
+ water_pos.mdV[0] += 1024.f * gDirAxes[dir][0];
+ water_pos.mdV[1] += 1024.f * gDirAxes[dir][1];
+
+ waterp->setPositionGlobal(water_pos);
+ waterp->setScale(water_scale);
+
+ gObjectList.updateActive(waterp);
+ }
+}
+
+
+void LLWorld::shiftRegions(const LLVector3& offset)
+{
+ for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i)
+ {
+ LLViewerRegion* region = *i;
+ region->updateRenderMatrix();
+ }
+
+ LLViewerPartSim::getInstance()->shift(offset);
+}
+
+LLViewerTexture* LLWorld::getDefaultWaterTexture()
+{
+ return mDefaultWaterTexturep;
+}
+
+void LLWorld::setSpaceTimeUSec(const U64 space_time_usec)
+{
+ mSpaceTimeUSec = space_time_usec;
+}
+
+U64 LLWorld::getSpaceTimeUSec() const
+{
+ return mSpaceTimeUSec;
+}
+
+void LLWorld::requestCacheMisses()
+{
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->requestCacheMisses();
+ }
+}
+
+void LLWorld::getInfo(LLSD& info)
+{
+ LLSD region_info;
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ regionp->getInfo(region_info);
+ info["World"].append(region_info);
+ }
+}
+
+void LLWorld::disconnectRegions()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ for (region_list_t::iterator iter = mRegionList.begin();
+ iter != mRegionList.end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ if (regionp == gAgent.getRegion())
+ {
+ // Skip the main agent
+ continue;
+ }
+
+ llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl;
+ msg->newMessageFast(_PREHASH_AgentQuitCopy);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_FuseBlock);
+ msg->addU32Fast(_PREHASH_ViewerCircuitCode, gMessageSystem->mOurCircuitCode);
+ msg->sendMessage(regionp->getHost());
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim");
+
+void process_enable_simulator(LLMessageSystem *msg, void **user_data)
+{
+ LLFastTimer t(FTM_ENABLE_SIMULATOR);
+ // enable the appropriate circuit for this simulator and
+ // add its values into the gSimulator structure
+ U64 handle;
+ U32 ip_u32;
+ U16 port;
+
+ msg->getU64Fast(_PREHASH_SimulatorInfo, _PREHASH_Handle, handle);
+ msg->getIPAddrFast(_PREHASH_SimulatorInfo, _PREHASH_IP, ip_u32);
+ msg->getIPPortFast(_PREHASH_SimulatorInfo, _PREHASH_Port, port);
+
+ // which simulator should we modify?
+ LLHost sim(ip_u32, port);
+
+ // Viewer trusts the simulator.
+ msg->enableCircuit(sim, TRUE);
+ LLWorld::getInstance()->addRegion(handle, sim);
+
+ // give the simulator a message it can use to get ip and port
+ llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl;
+ msg->newMessageFast(_PREHASH_UseCircuitCode);
+ msg->nextBlockFast(_PREHASH_CircuitCode);
+ msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
+ msg->sendReliable(sim);
+}
+
+class LLEstablishAgentCommunication : public LLHTTPNode
+{
+ LOG_CLASS(LLEstablishAgentCommunication);
+public:
+ virtual void describe(Description& desc) const
+ {
+ desc.shortInfo("seed capability info for a region");
+ desc.postAPI();
+ desc.input(
+ "{ seed-capability: ..., sim-ip: ..., sim-port }");
+ desc.source(__FILE__, __LINE__);
+ }
+
+ virtual void post(ResponsePtr response, const LLSD& context, const LLSD& input) const
+ {
+ if (!input["body"].has("agent-id") ||
+ !input["body"].has("sim-ip-and-port") ||
+ !input["body"].has("seed-capability"))
+ {
+ llwarns << "invalid parameters" << llendl;
+ return;
+ }
+
+ LLHost sim(input["body"]["sim-ip-and-port"].asString());
+
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim);
+ if (!regionp)
+ {
+ llwarns << "Got EstablishAgentCommunication for unknown region "
+ << sim << llendl;
+ return;
+ }
+ regionp->setSeedCapability(input["body"]["seed-capability"]);
+ }
+};
+
+// disable the circuit to this simulator
+// Called in response to "DisableSimulator" message.
+void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLHost host = mesgsys->getSender();
+
+ //llinfos << "Disabling simulator with message from " << host << llendl;
+ LLWorld::getInstance()->removeRegion(host);
+
+ mesgsys->disableCircuit(host);
+}
+
+
+void process_region_handshake(LLMessageSystem* msg, void** user_data)
+{
+ LLHost host = msg->getSender();
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(host);
+ if (!regionp)
+ {
+ llwarns << "Got region handshake for unknown region "
+ << host << llendl;
+ return;
+ }
+
+ regionp->unpackRegionHandshake();
+}
+
+
+void send_agent_pause()
+{
+ // *NOTE:Mani Pausing the mainloop timeout. Otherwise a long modal event may cause
+ // the thread monitor to timeout.
+ LLAppViewer::instance()->pauseMainloopTimeout();
+
+ // Note: used to check for LLWorld initialization before it became a singleton.
+ // Rather than just remove this check I'm changing it to assure that the message
+ // system has been initialized. -MG
+ if (!gMessageSystem)
+ {
+ return;
+ }
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentPause);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
+
+ gAgentPauseSerialNum++;
+ gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ gMessageSystem->sendReliable(regionp->getHost());
+ }
+
+ gObjectList.mWasPaused = TRUE;
+}
+
+
+void send_agent_resume()
+{
+ // Note: used to check for LLWorld initialization before it became a singleton.
+ // Rather than just remove this check I'm changing it to assure that the message
+ // system has been initialized. -MG
+ if (!gMessageSystem)
+ {
+ return;
+ }
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentResume);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
+
+ gAgentPauseSerialNum++;
+ gMessageSystem->addU32Fast(_PREHASH_SerialNum, gAgentPauseSerialNum);
+
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ gMessageSystem->sendReliable(regionp->getHost());
+ }
+
+ // Reset the FPS counter to avoid an invalid fps
+ LLViewerStats::getInstance()->mFPSStat.start();
+
+ LLAppViewer::instance()->resumeMainloopTimeout();
+}
+
+static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin)
+{
+ LLVector3d pos_global;
+ LLVector3 pos_local;
+ U8 bits;
+
+ bits = compact_local & 0xFF;
+ pos_local.mV[VZ] = F32(bits) * 4.f;
+ compact_local >>= 8;
+
+ bits = compact_local & 0xFF;
+ pos_local.mV[VY] = (F32)bits;
+ compact_local >>= 8;
+
+ bits = compact_local & 0xFF;
+ pos_local.mV[VX] = (F32)bits;
+
+ pos_global.setVec( pos_local );
+ pos_global += region_origin;
+ return pos_global;
+}
+
+void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positions, const LLVector3d& relative_to, F32 radius) const
+{
+ if(avatar_ids != NULL)
+ {
+ avatar_ids->clear();
+ }
+ if(positions != NULL)
+ {
+ positions->clear();
+ }
+ // get the list of avatars from the character list first, so distances are correct
+ // when agent is above 1020m and other avatars are nearby
+ for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end(); ++iter)
+ {
+ LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter;
+ if(!pVOAvatar->isDead() && !pVOAvatar->isSelf())
+ {
+ LLUUID uuid = pVOAvatar->getID();
+ if(!uuid.isNull())
+ {
+ LLVector3d pos_global = pVOAvatar->getPositionGlobal();
+ if(dist_vec(pos_global, relative_to) <= radius)
+ {
+ if(positions != NULL)
+ {
+ positions->push_back(pos_global);
+ }
+ if(avatar_ids !=NULL)
+ {
+ avatar_ids->push_back(uuid);
+ }
+ }
+ }
+ }
+ }
+ // region avatars added for situations where radius is greater than RenderFarClip
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* regionp = *iter;
+ const LLVector3d& origin_global = regionp->getOriginGlobal();
+ S32 count = regionp->mMapAvatars.count();
+ for (S32 i = 0; i < count; i++)
+ {
+ LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.get(i), origin_global);
+ if(dist_vec(pos_global, relative_to) <= radius)
+ {
+ LLUUID uuid = regionp->mMapAvatarIDs.get(i);
+ // if this avatar doesn't already exist in the list, add it
+ if(uuid.notNull() && avatar_ids!=NULL && std::find(avatar_ids->begin(), avatar_ids->end(), uuid) == avatar_ids->end())
+ {
+ if(positions != NULL)
+ {
+ positions->push_back(pos_global);
+ }
+ avatar_ids->push_back(uuid);
+ }
+ }
+ }
+ }
+}
+
+
+LLHTTPRegistration<LLEstablishAgentCommunication>
+ gHTTPRegistrationEstablishAgentCommunication(
+ "/message/EstablishAgentCommunication");
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 8ef3a3b839..8cdb615686 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -1745,7 +1745,7 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
// Invoke the event details floater if someone is clicking on an event.
LLSD params(LLSD::emptyArray());
params.append(event_id);
- LLCommandDispatcher::dispatch("event", params, LLSD(), NULL, true);
+ LLCommandDispatcher::dispatch("event", params, LLSD(), NULL, "clicked", true);
break;
}
case MAP_ITEM_LAND_FOR_SALE:
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d18e1de60c..a533be675c 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1,9790 +1,9786 @@
-/**
- * @file pipeline.cpp
- * @brief Rendering pipeline.
- *
- * $LicenseInfo:firstyear=2005&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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "pipeline.h"
-
-// library includes
-#include "llaudioengine.h" // For debugging.
-#include "imageids.h"
-#include "llerror.h"
-#include "llviewercontrol.h"
-#include "llfasttimer.h"
-#include "llfontgl.h"
-#include "llmemtype.h"
-#include "llnamevalue.h"
-#include "llpointer.h"
-#include "llprimitive.h"
-#include "llvolume.h"
-#include "material_codes.h"
-#include "timing.h"
-#include "v3color.h"
-#include "llui.h"
-#include "llglheaders.h"
-#include "llrender.h"
-#include "llwindow.h" // swapBuffers()
-
-// newview includes
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolavatar.h"
-#include "lldrawpoolground.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpooltree.h"
-#include "lldrawpoolwater.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfloatertelehub.h"
-#include "llfloaterreg.h"
-#include "llgldbg.h"
-#include "llhudmanager.h"
-#include "llhudnametag.h"
-#include "llhudtext.h"
-#include "lllightconstants.h"
-#include "llmeshrepository.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "lltracker.h"
-#include "lltool.h"
-#include "lltoolmgr.h"
-#include "llviewercamera.h"
-#include "llviewermediafocus.h"
-#include "llviewertexturelist.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h" // for audio debugging.
-#include "llviewerwindow.h" // For getSpinAxis
-#include "llvoavatarself.h"
-#include "llvoground.h"
-#include "llvosky.h"
-#include "llvotree.h"
-#include "llvovolume.h"
-#include "llvosurfacepatch.h"
-#include "llvowater.h"
-#include "llvotree.h"
-#include "llvopartgroup.h"
-#include "llworld.h"
-#include "llcubemap.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llviewerjoystick.h"
-#include "llviewerdisplay.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llspatialpartition.h"
-#include "llmutelist.h"
-#include "lltoolpie.h"
-#include "llcurl.h"
-
-
-void check_stack_depth(S32 stack_depth)
-{
- if (gDebugGL || gDebugSession)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth != stack_depth)
- {
- if (gDebugSession)
- {
- ll_fail("GL matrix stack corrupted.");
- }
- else
- {
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- }
- }
-}
-
-#ifdef _DEBUG
-// Debug indices is disabled for now for debug performance - djs 4/24/02
-//#define DEBUG_INDICES
-#else
-//#define DEBUG_INDICES
-#endif
-
-const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
-const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
-const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
-const U32 REFLECTION_MAP_RES = 128;
-
-// Max number of occluders to search for. JC
-const S32 MAX_OCCLUDER_COUNT = 2;
-
-extern S32 gBoxFrame;
-//extern BOOL gHideSelectedObjects;
-extern BOOL gDisplaySwapBuffers;
-extern BOOL gDebugGL;
-
-// hack counter for rendering a fixed number of frames after toggling
-// fullscreen to work around DEV-5361
-static S32 sDelayedVBOEnable = 0;
-
-BOOL gAvatarBacklight = FALSE;
-
-BOOL gDebugPipeline = FALSE;
-LLPipeline gPipeline;
-const LLMatrix4* gGLLastMatrix = NULL;
-
-LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
-LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
-LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
-LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
-LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
-LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
-LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
-LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
-LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
-LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
-LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
-LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
-LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
-LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
-LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
-LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
-LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
-LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
-LLFastTimer::DeclareTimer FTM_POOLS("Pools");
-LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
-LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
-LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
-LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
-LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
-
-
-static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
-static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
-
-//----------------------------------------
-std::string gPoolNames[] =
-{
- // Correspond to LLDrawpool enum render type
- "NONE",
- "POOL_SIMPLE",
- "POOL_GROUND",
- "POOL_FULLBRIGHT",
- "POOL_BUMP",
- "POOL_TERRAIN,"
- "POOL_SKY",
- "POOL_WL_SKY",
- "POOL_TREE",
- "POOL_GRASS",
- "POOL_INVISIBLE",
- "POOL_AVATAR",
- "POOL_VOIDWATER",
- "POOL_WATER",
- "POOL_GLOW",
- "POOL_ALPHA"
-};
-
-void drawBox(const LLVector3& c, const LLVector3& r);
-void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
-
-U32 nhpo2(U32 v)
-{
- U32 r = 1;
- while (r < v) {
- r *= 2;
- }
- return r;
-}
-
-glh::matrix4f glh_copy_matrix(GLdouble* src)
-{
- glh::matrix4f ret;
- for (U32 i = 0; i < 16; i++)
- {
- ret.m[i] = (F32) src[i];
- }
- return ret;
-}
-
-glh::matrix4f glh_get_current_modelview()
-{
- return glh_copy_matrix(gGLModelView);
-}
-
-glh::matrix4f glh_get_current_projection()
-{
- return glh_copy_matrix(gGLProjection);
-}
-
-glh::matrix4f glh_get_last_modelview()
-{
- return glh_copy_matrix(gGLLastModelView);
-}
-
-glh::matrix4f glh_get_last_projection()
-{
- return glh_copy_matrix(gGLLastProjection);
-}
-
-void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst)
-{
- for (U32 i = 0; i < 16; i++)
- {
- dst[i] = src.m[i];
- }
-}
-
-void glh_set_current_modelview(const glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLModelView);
-}
-
-void glh_set_current_projection(glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLProjection);
-}
-
-glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
-{
- glh::matrix4f ret(
- 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
- 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
- 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
- 0.f, 0.f, 0.f, 1.f);
-
- return ret;
-}
-
-void display_update_camera();
-//----------------------------------------
-
-S32 LLPipeline::sCompiles = 0;
-
-BOOL LLPipeline::sPickAvatar = TRUE;
-BOOL LLPipeline::sDynamicLOD = TRUE;
-BOOL LLPipeline::sShowHUDAttachments = TRUE;
-BOOL LLPipeline::sRenderMOAPBeacons = FALSE;
-BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
-BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
-BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
-BOOL LLPipeline::sRenderParticleBeacons = FALSE;
-BOOL LLPipeline::sRenderSoundBeacons = FALSE;
-BOOL LLPipeline::sRenderBeacons = FALSE;
-BOOL LLPipeline::sRenderHighlight = TRUE;
-BOOL LLPipeline::sForceOldBakedUpload = FALSE;
-S32 LLPipeline::sUseOcclusion = 0;
-BOOL LLPipeline::sDelayVBUpdate = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
-BOOL LLPipeline::sDisableShaders = FALSE;
-BOOL LLPipeline::sRenderBump = TRUE;
-BOOL LLPipeline::sBakeSunlight = FALSE;
-BOOL LLPipeline::sNoAlpha = FALSE;
-BOOL LLPipeline::sUseTriStrips = TRUE;
-BOOL LLPipeline::sUseFarClip = TRUE;
-BOOL LLPipeline::sShadowRender = FALSE;
-BOOL LLPipeline::sWaterReflections = FALSE;
-BOOL LLPipeline::sRenderGlow = FALSE;
-BOOL LLPipeline::sReflectionRender = FALSE;
-BOOL LLPipeline::sImpostorRender = FALSE;
-BOOL LLPipeline::sUnderWaterRender = FALSE;
-BOOL LLPipeline::sTextureBindTest = FALSE;
-BOOL LLPipeline::sRenderFrameTest = FALSE;
-BOOL LLPipeline::sRenderAttachedLights = TRUE;
-BOOL LLPipeline::sRenderAttachedParticles = TRUE;
-BOOL LLPipeline::sRenderDeferred = FALSE;
-S32 LLPipeline::sVisibleLightCount = 0;
-F32 LLPipeline::sMinRenderSize = 0.f;
-
-
-static LLCullResult* sCull = NULL;
-
-static const U32 gl_cube_face[] =
-{
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
-};
-
-void validate_framebuffer_object();
-
-
-void addDeferredAttachments(LLRenderTarget& target)
-{
- target.addColorAttachment(GL_RGBA); //specular
- target.addColorAttachment(GL_RGBA); //normal+z
-}
-
-LLPipeline::LLPipeline() :
- mBackfaceCull(FALSE),
- mBatchCount(0),
- mMatrixOpCount(0),
- mTextureMatrixOps(0),
- mMaxBatchSize(0),
- mMinBatchSize(0),
- mMeanBatchSize(0),
- mTrianglesDrawn(0),
- mNumVisibleNodes(0),
- mVerticesRelit(0),
- mLightingChanges(0),
- mGeometryChanges(0),
- mNumVisibleFaces(0),
-
- mInitialized(FALSE),
- mVertexShadersEnabled(FALSE),
- mVertexShadersLoaded(0),
- mRenderDebugFeatureMask(0),
- mRenderDebugMask(0),
- mOldRenderDebugMask(0),
- mGroupQ1Locked(false),
- mGroupQ2Locked(false),
- mLastRebuildPool(NULL),
- mAlphaPool(NULL),
- mSkyPool(NULL),
- mTerrainPool(NULL),
- mWaterPool(NULL),
- mGroundPool(NULL),
- mSimplePool(NULL),
- mFullbrightPool(NULL),
- mInvisiblePool(NULL),
- mGlowPool(NULL),
- mBumpPool(NULL),
- mWLSkyPool(NULL),
- mLightMask(0),
- mLightMovingMask(0),
- mLightingDetail(0),
- mScreenWidth(0),
- mScreenHeight(0)
-{
- mNoiseMap = 0;
- mTrueNoiseMap = 0;
- mLightFunc = 0;
-}
-
-void LLPipeline::init()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
-
- sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
- LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
- sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
- sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
-
- mInitialized = TRUE;
-
- stop_glerror();
-
- //create render pass pools
- getPool(LLDrawPool::POOL_ALPHA);
- getPool(LLDrawPool::POOL_SIMPLE);
- getPool(LLDrawPool::POOL_GRASS);
- getPool(LLDrawPool::POOL_FULLBRIGHT);
- getPool(LLDrawPool::POOL_INVISIBLE);
- getPool(LLDrawPool::POOL_BUMP);
- getPool(LLDrawPool::POOL_GLOW);
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
- resetFrameStats();
-
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
- }
-
- mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
- mRenderDebugMask = 0; // All debug starts off
-
- // Don't turn on ground when this is set
- // Mac Books with intel 950s need this
- if(!gSavedSettings.getBOOL("RenderGround"))
- {
- toggleRenderType(RENDER_TYPE_GROUND);
- }
-
- // make sure RenderPerformanceTest persists (hackity hack hack)
- // disables non-object rendering (UI, sky, water, etc)
- if (gSavedSettings.getBOOL("RenderPerformanceTest"))
- {
- gSavedSettings.setBOOL("RenderPerformanceTest", FALSE);
- gSavedSettings.setBOOL("RenderPerformanceTest", TRUE);
- }
-
- mOldRenderDebugMask = mRenderDebugMask;
-
- mBackfaceCull = TRUE;
-
- stop_glerror();
-
- // Enable features
-
- LLViewerShaderMgr::instance()->setShaders();
-
- stop_glerror();
-
- for (U32 i = 0; i < 2; ++i)
- {
- mSpotLightFade[i] = 1.f;
- }
-
- setLightingDetail(-1);
-}
-
-LLPipeline::~LLPipeline()
-{
-
-}
-
-void LLPipeline::cleanup()
-{
- assertInitialized();
-
- mGroupQ1.clear() ;
- mGroupQ2.clear() ;
-
- for(pool_set_t::iterator iter = mPools.begin();
- iter != mPools.end(); )
- {
- pool_set_t::iterator curiter = iter++;
- LLDrawPool* poolp = *curiter;
- if (poolp->isFacePool())
- {
- LLFacePool* face_pool = (LLFacePool*) poolp;
- if (face_pool->mReferences.empty())
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
- else
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
-
- if (!mTerrainPools.empty())
- {
- llwarns << "Terrain Pools not cleaned up" << llendl;
- }
- if (!mTreePools.empty())
- {
- llwarns << "Tree Pools not cleaned up" << llendl;
- }
-
- delete mAlphaPool;
- mAlphaPool = NULL;
- delete mSkyPool;
- mSkyPool = NULL;
- delete mTerrainPool;
- mTerrainPool = NULL;
- delete mWaterPool;
- mWaterPool = NULL;
- delete mGroundPool;
- mGroundPool = NULL;
- delete mSimplePool;
- mSimplePool = NULL;
- delete mFullbrightPool;
- mFullbrightPool = NULL;
- delete mInvisiblePool;
- mInvisiblePool = NULL;
- delete mGlowPool;
- mGlowPool = NULL;
- delete mBumpPool;
- mBumpPool = NULL;
- // don't delete wl sky pool it was handled above in the for loop
- //delete mWLSkyPool;
- mWLSkyPool = NULL;
-
- releaseGLBuffers();
-
- mFaceSelectImagep = NULL;
-
- mMovedBridge.clear();
-
- mInitialized = FALSE;
-}
-
-//============================================================================
-
-void LLPipeline::destroyGL()
-{
- stop_glerror();
- unloadShaders();
- mHighlightFaces.clear();
-
- resetDrawOrders();
-
- resetVertexBuffers();
-
- releaseGLBuffers();
-
- if (LLVertexBuffer::sEnableVBOs)
- {
- // render 30 frames after switching to work around DEV-5361
- sDelayedVBOEnable = 30;
- LLVertexBuffer::sEnableVBOs = FALSE;
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
-
-void LLPipeline::resizeScreenTexture()
-{
- LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
- if (gPipeline.canUseVertexShaders() && assertInitialized())
- {
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- allocateScreenBuffer(resX,resY);
- }
-}
-
-void LLPipeline::allocatePhysicsBuffer()
-{
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY)
- {
- mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- if (mSampleBuffer.getWidth() == mPhysicsDisplay.getWidth() &&
- mSampleBuffer.getHeight() == mPhysicsDisplay.getHeight())
- {
- mPhysicsDisplay.setSampleBuffer(&mSampleBuffer);
- }
- }
-}
-
-void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
-{
- // remember these dimensions
- mScreenWidth = resX;
- mScreenHeight = resY;
-
- //never use more than 4 samples for render targets
- U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4);
- if (gGLManager.mIsATI)
- { //disable multisampling of render targets where ATI is involved
- samples = 0;
- }
-
- U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-
- if (res_mod > 1 && res_mod < resX && res_mod < resY)
- {
- resX /= res_mod;
- resY /= res_mod;
- }
-
- if (gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- }
-
- if (LLPipeline::sRenderDeferred)
- {
- S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
- BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO");
- bool gi = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED);
-
- //allocate deferred rendering color buffers
- mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- addDeferredAttachments(mDeferredScreen);
-
- mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
-
- if (shadow_detail > 0 || ssao)
- { //only need mDeferredLight[0] for shadows OR ssao
- mDeferredLight[0].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
- else
- {
- mDeferredLight[0].release();
- }
-
- if (ssao)
- { //only need mDeferredLight[1] for ssao
- mDeferredLight[1].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
- else
- {
- mDeferredLight[1].release();
- }
-
- if (gi)
- { //only need mDeferredLight[2] and mGIMapPost for gi
- mDeferredLight[2].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- for (U32 i = 0; i < 2; i++)
- {
- mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
- }
- else
- {
- mDeferredLight[2].release();
-
- for (U32 i = 0; i < 2; i++)
- {
- mGIMapPost[i].release();
- }
- }
-
- F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
-
- //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
- U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
-
- if (shadow_detail > 0)
- { //allocate 4 sun shadow maps
- for (U32 i = 0; i < 4; i++)
- {
- mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
- }
- else
- {
- for (U32 i = 0; i < 4; i++)
- {
- mShadow[i].release();
- }
- }
-
- U32 width = nhpo2(U32(resX*scale))/2;
- U32 height = width;
-
- if (shadow_detail > 1)
- { //allocate two spot shadow maps
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
- }
- }
- else
- {
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].release();
- }
- }
-
- width = nhpo2(resX)/2;
- height = nhpo2(resY)/2;
- mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
- }
- else
- {
- for (U32 i = 0; i < 3; i++)
- {
- mDeferredLight[i].release();
- }
- for (U32 i = 0; i < 2; i++)
- {
- mGIMapPost[i].release();
- }
- for (U32 i = 0; i < 6; i++)
- {
- mShadow[i].release();
- }
- mScreen.release();
- mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
- mDeferredDepth.release();
- mEdgeMap.release();
- mLuminanceMap.release();
-
- mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- }
-
- if (LLRenderTarget::sUseFBO && samples > 1)
- {
- mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
- if (LLPipeline::sRenderDeferred)
- {
- addDeferredAttachments(mSampleBuffer);
- mDeferredScreen.setSampleBuffer(&mSampleBuffer);
- mEdgeMap.setSampleBuffer(&mSampleBuffer);
- }
-
- mScreen.setSampleBuffer(&mSampleBuffer);
-
- stop_glerror();
- }
- else
- {
- mSampleBuffer.release();
- }
-
- if (LLPipeline::sRenderDeferred)
- { //share depth buffer between deferred targets
- mDeferredScreen.shareDepthBuffer(mScreen);
- for (U32 i = 0; i < 3; i++)
- { //share stencil buffer with screen space lightmap to stencil out sky
- if (mDeferredLight[i].getTexture(0))
- {
- mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
- }
- }
- }
-
- gGL.getTexUnit(0)->disable();
-
- stop_glerror();
-
-}
-
-//static
-void LLPipeline::updateRenderDeferred()
-{
- BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") &&
- LLRenderTarget::sUseFBO &&
- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
- gSavedSettings.getBOOL("VertexShaderEnable") &&
- gSavedSettings.getBOOL("RenderAvatarVP") &&
- gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
- !gUseWireframe;
-
- sRenderDeferred = deferred;
- if (deferred)
- { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all
- sRenderGlow = TRUE;
- }
-}
-
-void LLPipeline::releaseGLBuffers()
-{
- assertInitialized();
-
- if (mNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mNoiseMap);
- mNoiseMap = 0;
- }
-
- if (mTrueNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mTrueNoiseMap);
- mTrueNoiseMap = 0;
- }
-
- if (mLightFunc)
- {
- LLImageGL::deleteTextures(1, &mLightFunc);
- mLightFunc = 0;
- }
-
- mWaterRef.release();
- mWaterDis.release();
- mScreen.release();
- mPhysicsDisplay.release();
- mUIScreen.release();
- mSampleBuffer.release();
- mDeferredScreen.release();
- mDeferredDepth.release();
- for (U32 i = 0; i < 3; i++)
- {
- mDeferredLight[i].release();
- }
-
- mEdgeMap.release();
- mGIMap.release();
- mGIMapPost[0].release();
- mGIMapPost[1].release();
- mHighlight.release();
- mLuminanceMap.release();
-
- for (U32 i = 0; i < 6; i++)
- {
- mShadow[i].release();
- }
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].release();
- }
-
- LLVOAvatar::resetImpostors();
-}
-
-void LLPipeline::createGLBuffers()
-{
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
- assertInitialized();
-
- updateRenderDeferred();
-
- if (LLPipeline::sWaterReflections)
- { //water reflection texture
- U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
-
- mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
- mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
- }
-
- mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
-
- stop_glerror();
-
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- if (LLPipeline::sRenderGlow)
- { //screen space glow buffers
- const U32 glow_res = llmax(1,
- llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
- }
-
- allocateScreenBuffer(resX,resY);
- mScreenWidth = 0;
- mScreenHeight = 0;
- }
-
- if (sRenderDeferred)
- {
- if (!mNoiseMap)
- {
- const U32 noiseRes = 128;
- LLVector3 noise[noiseRes*noiseRes];
-
- F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
- for (U32 i = 0; i < noiseRes*noiseRes; ++i)
- {
- noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
- noise[i].normVec();
- noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
- }
-
- LLImageGL::generateTextures(1, &mNoiseMap);
-
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mTrueNoiseMap)
- {
- const U32 noiseRes = 128;
- F32 noise[noiseRes*noiseRes*3];
- for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
- {
- noise[i] = ll_frand()*2.0-1.0;
- }
-
- LLImageGL::generateTextures(1, &mTrueNoiseMap);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mLightFunc)
- {
- U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
- U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
- U8* lg = new U8[lightResX*lightResY];
-
- for (U32 y = 0; y < lightResY; ++y)
- {
- for (U32 x = 0; x < lightResX; ++x)
- {
- //spec func
- F32 sa = (F32) x/(lightResX-1);
- F32 spec = (F32) y/(lightResY-1);
- //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
-
- //F32 sp = acosf(sa)/(1.f-spec);
-
- sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
- F32 a = acosf(sa*0.25f+0.75f);
- F32 m = llmax(0.5f-spec*0.5f, 0.001f);
- F32 t2 = tanf(a)/m;
- t2 *= t2;
-
- F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
- F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
-
- lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
- }
- }
-
- LLImageGL::generateTextures(1, &mLightFunc);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
-
- delete [] lg;
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredGI"))
- {
- mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE);
- addDeferredAttachments(mGIMap);
- }
- }
-}
-
-void LLPipeline::restoreGL()
-{
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
- assertInitialized();
-
- if (mVertexShadersEnabled)
- {
- LLViewerShaderMgr::instance()->setShaders();
- }
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->restoreGL();
- }
- }
- }
-}
-
-
-BOOL LLPipeline::canUseVertexShaders()
-{
- if (sDisableShaders ||
- !gGLManager.mHasVertexShader ||
- !gGLManager.mHasFragmentShader ||
- !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
- (assertInitialized() && mVertexShadersLoaded != 1) )
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-BOOL LLPipeline::canUseWindLightShaders() const
-{
- return (!LLPipeline::sDisableShaders &&
- gWLSkyProgram.mProgramObject != 0 &&
- LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
-}
-
-BOOL LLPipeline::canUseWindLightShadersOnObjects() const
-{
- return (canUseWindLightShaders()
- && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
-}
-
-BOOL LLPipeline::canUseAntiAliasing() const
-{
- return TRUE;
-}
-
-void LLPipeline::unloadShaders()
-{
- LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
- LLViewerShaderMgr::instance()->unloadShaders();
-
- mVertexShadersLoaded = 0;
-}
-
-void LLPipeline::assertInitializedDoError()
-{
- llerrs << "LLPipeline used when uninitialized." << llendl;
-}
-
-//============================================================================
-
-void LLPipeline::enableShadows(const BOOL enable_shadows)
-{
- //should probably do something here to wrangle shadows....
-}
-
-S32 LLPipeline::getMaxLightingDetail() const
-{
- /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
- {
- return 3;
- }
- else*/
- {
- return 1;
- }
-}
-
-S32 LLPipeline::setLightingDetail(S32 level)
-{
- LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
-
- if (level < 0)
- {
- if (gSavedSettings.getBOOL("RenderLocalLights"))
- {
- level = 1;
- }
- else
- {
- level = 0;
- }
- }
- level = llclamp(level, 0, getMaxLightingDetail());
- mLightingDetail = level;
-
- return mLightingDetail;
-}
-
-class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
-{
-public:
- const std::set<LLViewerFetchedTexture*>& mTextures;
-
- LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
-
- virtual void visit(const LLOctreeNode<LLDrawable>* node)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-
- if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
- {
- for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
- {
- for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
- {
- LLDrawInfo* params = *j;
- LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
- if (tex && mTextures.find(tex) != mTextures.end())
- {
- group->setState(LLSpatialGroup::GEOM_DIRTY);
- }
- }
- }
- }
-
- for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- traverse(bridge->mOctree);
- }
- }
-};
-
-// Called when a texture changes # of channels (causes faces to move to alpha pool)
-void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
-{
- assertInitialized();
-
- // *TODO: This is inefficient and causes frame spikes; need a better way to do this
- // Most of the time is spent in dirty.traverse.
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (poolp->isFacePool())
- {
- ((LLFacePool*) poolp)->dirtyTextures(textures);
- }
- }
-
- LLOctreeDirtyTexture dirty(textures);
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- dirty.traverse(part->mOctree);
- }
- }
- }
-}
-
-LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
-{
- assertInitialized();
-
- LLDrawPool *poolp = NULL;
- switch( type )
- {
- case LLDrawPool::POOL_SIMPLE:
- poolp = mSimplePool;
- break;
-
- case LLDrawPool::POOL_GRASS:
- poolp = mGrassPool;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- poolp = mFullbrightPool;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- poolp = mInvisiblePool;
- break;
-
- case LLDrawPool::POOL_GLOW:
- poolp = mGlowPool;
- break;
-
- case LLDrawPool::POOL_TREE:
- poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_BUMP:
- poolp = mBumpPool;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- poolp = mAlphaPool;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- poolp = mSkyPool;
- break;
-
- case LLDrawPool::POOL_WATER:
- poolp = mWaterPool;
- break;
-
- case LLDrawPool::POOL_GROUND:
- poolp = mGroundPool;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- poolp = mWLSkyPool;
- break;
-
- default:
- llassert(0);
- llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
- break;
- }
-
- return poolp;
-}
-
-
-LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- LLDrawPool *poolp = findPool(type, tex0);
- if (poolp)
- {
- return poolp;
- }
-
- LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
- addPool( new_poolp );
-
- return new_poolp;
-}
-
-
-// static
-LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- U32 type = getPoolTypeFromTE(te, imagep);
- return gPipeline.getPool(type, imagep);
-}
-
-//static
-U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
-
- if (!te || !imagep)
- {
- return 0;
- }
-
- bool alpha = te->getColor().mV[3] < 0.999f;
- if (imagep)
- {
- alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
- }
-
- if (alpha)
- {
- return LLDrawPool::POOL_ALPHA;
- }
- else if ((te->getBumpmap() || te->getShiny()))
- {
- return LLDrawPool::POOL_BUMP;
- }
- else
- {
- return LLDrawPool::POOL_SIMPLE;
- }
-}
-
-
-void LLPipeline::addPool(LLDrawPool *new_poolp)
-{
- LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
- assertInitialized();
- mPools.insert(new_poolp);
- addToQuickLookup( new_poolp );
-}
-
-void LLPipeline::allocDrawable(LLViewerObject *vobj)
-{
- LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
- LLDrawable *drawable = new LLDrawable();
- vobj->mDrawable = drawable;
-
- drawable->mVObjp = vobj;
-
- //encompass completely sheared objects by taking
- //the most extreme point possible (<1,1,0.5>)
- drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
- if (vobj->isOrphaned())
- {
- drawable->setState(LLDrawable::FORCE_INVISIBLE);
- }
- drawable->updateXform(TRUE);
-}
-
-
-static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set");
-static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
-
-void LLPipeline::unlinkDrawable(LLDrawable *drawable)
-{
- LLFastTimer t(FTM_UNLINK);
-
- assertInitialized();
-
- LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
-
- // Based on flags, remove the drawable from the queues that it's on.
- if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST);
- LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
- if (iter != mMovedList.end())
- {
- mMovedList.erase(iter);
- }
- }
-
- if (drawablep->getSpatialGroup())
- {
- LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
- if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
- {
-#ifdef LL_RELEASE_FOR_DOWNLOAD
- llwarns << "Couldn't remove object from spatial group!" << llendl;
-#else
- llerrs << "Couldn't remove object from spatial group!" << llendl;
-#endif
- }
- }
-
- {
- LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
- mLights.erase(drawablep);
-
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- if (iter->drawable == drawablep)
- {
- mNearbyLights.erase(iter);
- break;
- }
- }
- }
-
- {
- LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
- HighlightItem item(drawablep);
- mHighlightSet.erase(item);
-
- if (mHighlightObject == drawablep)
- {
- mHighlightObject = NULL;
- }
- }
-
- for (U32 i = 0; i < 2; ++i)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- mShadowSpotLight[i] = NULL;
- }
-
- if (mTargetShadowSpotLight[i] == drawablep)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
- }
-
-
-}
-
-U32 LLPipeline::addObject(LLViewerObject *vobj)
-{
- LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
- if (gNoRender)
- {
- return 0;
- }
-
- if (gSavedSettings.getBOOL("RenderDelayCreation"))
- {
- mCreateQ.push_back(vobj);
- }
- else
- {
- createObject(vobj);
- }
-
- return 1;
-}
-
-void LLPipeline::createObjects(F32 max_dtime)
-{
- LLFastTimer ftm(FTM_GEO_UPDATE);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
-
- LLTimer update_timer;
-
- while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
- {
- LLViewerObject* vobj = mCreateQ.front();
- if (!vobj->isDead())
- {
- createObject(vobj);
- }
- mCreateQ.pop_front();
- }
-
- //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
- //{
- // createObject(*iter);
- //}
-
- //mCreateQ.clear();
-}
-
-void LLPipeline::createObject(LLViewerObject* vobj)
-{
- LLDrawable* drawablep = vobj->mDrawable;
-
- if (!drawablep)
- {
- drawablep = vobj->createDrawable(this);
- }
- else
- {
- llerrs << "Redundant drawable creation!" << llendl;
- }
-
- llassert(drawablep);
-
- if (vobj->getParent())
- {
- vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
- }
- else
- {
- vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
- }
-
- markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
-
- if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes"))
- {
- // fun animated res
- drawablep->updateXform(TRUE);
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- drawablep->setScale(LLVector3(0,0,0));
- drawablep->makeActive();
- }
-}
-
-
-void LLPipeline::resetFrameStats()
-{
- assertInitialized();
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
-
- if (mBatchCount > 0)
- {
- mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
- }
- mTrianglesDrawn = 0;
- sCompiles = 0;
- mVerticesRelit = 0;
- mLightingChanges = 0;
- mGeometryChanges = 0;
- mNumVisibleFaces = 0;
-
- if (mOldRenderDebugMask != mRenderDebugMask)
- {
- gObjectList.clearDebugText();
- mOldRenderDebugMask = mRenderDebugMask;
- }
-
-}
-
-//external functions for asynchronous updating
-void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
-{
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
- drawablep->updateMove(); // returns done
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
-{
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
- drawablep->updateMove();
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
-{
- for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
- iter != moved_list.end(); )
- {
- LLDrawable::drawable_vector_t::iterator curiter = iter++;
- LLDrawable *drawablep = *curiter;
- BOOL done = TRUE;
- if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
- {
- done = drawablep->updateMove();
- }
- drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
- if (done)
- {
- drawablep->clearState(LLDrawable::ON_MOVE_LIST);
- iter = moved_list.erase(curiter);
- }
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
-static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
-
-void LLPipeline::updateMove()
-{
- LLFastTimer t(FTM_UPDATE_MOVE);
- LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
-
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
-
- assertInitialized();
-
- {
- static LLFastTimer::DeclareTimer ftm("Retexture");
- LLFastTimer t(ftm);
-
- for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
- iter != mRetexturedList.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
- if (drawablep && !drawablep->isDead())
- {
- drawablep->updateTexture();
- }
- }
- mRetexturedList.clear();
- }
-
- {
- static LLFastTimer::DeclareTimer ftm("Moved List");
- LLFastTimer t(ftm);
- updateMovedList(mMovedList);
- }
-
- //balance octrees
- {
- LLFastTimer ot(FTM_OCTREE_BALANCE);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->mOctree->balance();
- }
- }
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Culling and occlusion testing
-/////////////////////////////////////////////////////////////////////////////
-
-//static
-F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
-{
- LLVector3 lookAt = center - camera.getOrigin();
- F32 dist = lookAt.length();
-
- //ramp down distance for nearby objects
- //shrink dist by dist/16.
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
-
- //get area of circle around node
- F32 app_angle = atanf(size.length()/dist);
- F32 radius = app_angle*LLDrawable::sCurPixelAngle;
- return radius*radius * F_PI;
-}
-
-//static
-F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera)
-{
- LLVector4a origin;
- origin.load3(camera.getOrigin().mV);
-
- LLVector4a lookAt;
- lookAt.setSub(center, origin);
- F32 dist = lookAt.getLength3().getF32();
-
- //ramp down distance for nearby objects
- //shrink dist by dist/16.
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
-
- //get area of circle around node
- F32 app_angle = atanf(size.getLength3().getF32()/dist);
- F32 radius = app_angle*LLDrawable::sCurPixelAngle;
- return radius*radius * F_PI;
-}
-
-void LLPipeline::grabReferences(LLCullResult& result)
-{
- sCull = &result;
-}
-
-void LLPipeline::clearReferences()
-{
- sCull = NULL;
-}
-
-void check_references(LLSpatialGroup* group, LLDrawable* drawable)
-{
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- if (drawable == *i)
- {
- llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
- }
- }
-}
-
-void check_references(LLDrawable* drawable, LLFace* face)
-{
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- if (drawable->getFace(i) == face)
- {
- llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-}
-
-void check_references(LLSpatialGroup* group, LLFace* face)
-{
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- LLDrawable* drawable = *i;
- check_references(drawable, face);
- }
-}
-
-void LLPipeline::checkReferences(LLFace* face)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, face);
- }
-
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
- {
- LLDrawable* drawable = *iter;
- check_references(drawable, face);
- }
- }
-#endif
-}
-
-void LLPipeline::checkReferences(LLDrawable* drawable)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, drawable);
- }
-
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
- {
- if (drawable == *iter)
- {
- llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-#endif
-}
-
-void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info)
-{
- for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
- {
- LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
- for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
- {
- LLDrawInfo* params = *j;
- if (params == draw_info)
- {
- llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-}
-
-
-void LLPipeline::checkReferences(LLDrawInfo* draw_info)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- check_references(group, draw_info);
- }
- }
-#endif
-}
-
-void LLPipeline::checkReferences(LLSpatialGroup* group)
-{
-#if 0
- if (sCull)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- if (group == *iter)
- {
- llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
- }
- }
- }
-#endif
-}
-
-
-BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
-{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (part->visibleObjectsInFrustum(camera))
- {
- return TRUE;
- }
- }
- }
- }
- }
-
- return FALSE;
-}
-
-BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
-{
- const F32 X = 65536.f;
-
- min = LLVector3(X,X,X);
- max = LLVector3(-X,-X,-X);
-
- U32 saved_camera_id = LLViewerCamera::sCurCameraID;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- BOOL res = TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (!part->getVisibleExtents(camera, min, max))
- {
- res = FALSE;
- }
- }
- }
- }
- }
-
- LLViewerCamera::sCurCameraID = saved_camera_id;
-
- return res;
-}
-
-static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
-
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
-{
- LLFastTimer t(FTM_CULL);
- LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
-
- grabReferences(result);
-
- sCull->clear();
-
- BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
- !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
- LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- gPipeline.canUseVertexShaders() &&
- sRenderGlow;
-
- if (to_texture)
- {
- mScreen.bindTarget();
- }
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(false, false);
- }
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixd(gGLLastProjection);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLLastModelView);
-
-
- LLVertexBuffer::unbind();
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-
- //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling)
- LLViewerRegion* region = gAgent.getRegion();
- LLPlane plane;
-
- if (planep)
- {
- plane = *planep;
- }
- else
- {
- if (region)
- {
- LLVector3 pnorm;
- F32 height = region->getWaterHeight();
- if (water_clip < 0)
- { //camera is above water, clip plane points up
- pnorm.setVec(0,0,1);
- plane.setVec(pnorm, -height);
- }
- else if (water_clip > 0)
- { //camera is below water, clip plane points down
- pnorm = LLVector3(0,0,-1);
- plane.setVec(pnorm, height);
- }
- }
- }
-
- glh::matrix4f modelview = glh_get_last_modelview();
- glh::matrix4f proj = glh_get_last_projection();
- LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender);
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- if (water_clip != 0)
- {
- LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
- camera.setUserClipPlane(plane);
- }
- else
- {
- camera.disableUserClipPlane();
- }
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->cull(camera);
- }
- }
- }
- }
-
- camera.disableUserClipPlane();
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
- gSky.mVOSkyp.notNull() &&
- gSky.mVOSkyp->mDrawable.notNull())
- {
- gSky.mVOSkyp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
- gSky.updateCull();
- stop_glerror();
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
- !gPipeline.canUseWindLightShaders() &&
- gSky.mVOGroundp.notNull() &&
- gSky.mVOGroundp->mDrawable.notNull() &&
- !LLPipeline::sWaterReflections)
- {
- gSky.mVOGroundp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
- }
-
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(true, false);
- }
-
- if (to_texture)
- {
- mScreen.flush();
- }
-}
-
-void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
-{
- if (group->getData().empty())
- {
- return;
- }
-
- group->setVisible();
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- group->updateDistance(camera);
- }
-
- const F32 MINIMUM_PIXEL_AREA = 16.f;
-
- if (group->mPixelArea < MINIMUM_PIXEL_AREA)
- {
- return;
- }
-
- if (sMinRenderSize > 0.f &&
- llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
- {
- return;
- }
-
- assertInitialized();
-
- if (!group->mSpatialPartition->mRenderByGroup)
- { //render by drawable
- sCull->pushDrawableGroup(group);
- }
- else
- { //render by group
- sCull->pushVisibleGroup(group);
- }
-
- mNumVisibleNodes++;
-}
-
-void LLPipeline::markOccluder(LLSpatialGroup* group)
-{
- if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
- {
- LLSpatialGroup* parent = group->getParent();
-
- if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
- { //only mark top most occluders as active occlusion
- sCull->pushOcclusionGroup(group);
- group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
-
- if (parent &&
- !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
- parent->getElementCount() == 0 &&
- parent->needsUpdate())
- {
- sCull->pushOcclusionGroup(group);
- parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
- }
- }
-}
-
-void LLPipeline::doOcclusion(LLCamera& camera)
-{
- if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
- {
- LLVertexBuffer::unbind();
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
- {
- gGL.setColorMask(true, false, false, false);
- }
- else
- {
- gGL.setColorMask(false, false);
- }
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- LLGLDisable cull(GL_CULL_FACE);
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->doOcclusion(&camera);
- group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
-
- gGL.setColorMask(true, false);
- }
-}
-
-BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
-{
- BOOL update_complete = drawablep->updateGeometry(priority);
- if (update_complete && assertInitialized())
- {
- drawablep->setState(LLDrawable::BUILT);
- mGeometryChanges++;
- }
- return update_complete;
-}
-
-void LLPipeline::updateGL()
-{
- while (!LLGLUpdate::sGLQ.empty())
- {
- LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
- glu->updateGL();
- glu->mInQ = FALSE;
- LLGLUpdate::sGLQ.pop_front();
- }
-}
-
-void LLPipeline::rebuildPriorityGroups()
-{
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- gMeshRepo.notifyLoadedMeshes();
-
- mGroupQ1Locked = true;
- // Iterate through all drawables on the priority build queue,
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
- iter != mGroupQ1.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->rebuildGeom();
- group->clearState(LLSpatialGroup::IN_BUILD_Q1);
- }
-
- mGroupQ1.clear();
- mGroupQ1Locked = false;
-
-}
-
-void LLPipeline::rebuildGroups()
-{
- if (mGroupQ2.empty())
- {
- return;
- }
-
- mGroupQ2Locked = true;
- // Iterate through some drawables on the non-priority build queue
- S32 size = (S32) mGroupQ2.size();
- S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
-
- S32 count = 0;
-
- std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
-
- LLSpatialGroup::sg_vector_t::iterator iter;
- LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin();
-
- for (iter = mGroupQ2.begin();
- iter != mGroupQ2.end() && count <= min_count; ++iter)
- {
- LLSpatialGroup* group = *iter;
- last_iter = iter;
-
- if (!group->isDead())
- {
- group->rebuildGeom();
-
- if (group->mSpatialPartition->mRenderByGroup)
- {
- count++;
- }
- }
-
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
- }
-
- mGroupQ2.erase(mGroupQ2.begin(), ++last_iter);
-
- mGroupQ2Locked = false;
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::updateGeom(F32 max_dtime)
-{
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
- LLPointer<LLDrawable> drawablep;
-
- LLFastTimer t(FTM_GEO_UPDATE);
-
- assertInitialized();
-
- if (sDelayedVBOEnable > 0)
- {
- if (--sDelayedVBOEnable <= 0)
- {
- resetVertexBuffers();
- LLVertexBuffer::sEnableVBOs = TRUE;
- }
- }
-
- // notify various object types to reset internal cost metrics, etc.
- // for now, only LLVOVolume does this to throttle LOD changes
- LLVOVolume::preUpdateGeom();
-
- // Iterate through all drawables on the priority build queue,
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
- iter != mBuildQ1.end();)
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
- if (drawablep && !drawablep->isDead())
- {
- if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
- if (find != mBuildQ2.end())
- {
- mBuildQ2.erase(find);
- }
- }
-
- if (updateDrawableGeom(drawablep, TRUE))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
- mBuildQ1.erase(curiter);
- }
- }
- else
- {
- mBuildQ1.erase(curiter);
- }
- }
-
- // Iterate through some drawables on the non-priority build queue
- S32 min_count = 16;
- S32 size = (S32) mBuildQ2.size();
- if (size > 1024)
- {
- min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
- }
-
- S32 count = 0;
-
- max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
- LLSpatialGroup* last_group = NULL;
- LLSpatialBridge* last_bridge = NULL;
-
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
- iter != mBuildQ2.end(); )
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
-
- LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
- drawablep->getParent()->getSpatialBridge();
-
- if (drawablep->getSpatialGroup() != last_group &&
- (!last_bridge || bridge != last_bridge) &&
- (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
- {
- break;
- }
-
- //make sure updates don't stop in the middle of a spatial group
- //to avoid thrashing (objects are enqueued by group)
- last_group = drawablep->getSpatialGroup();
- last_bridge = bridge;
-
- BOOL update_complete = TRUE;
- if (!drawablep->isDead())
- {
- update_complete = updateDrawableGeom(drawablep, FALSE);
- count++;
- }
- if (update_complete)
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- mBuildQ2.erase(curiter);
- }
- }
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
-
- if(drawablep && !drawablep->isDead())
- {
- if (drawablep->isSpatialBridge())
- {
- const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
- llassert(root); // trying to catch a bad assumption
- if (root && // // this test may not be needed, see above
- root->getVObj()->isAttachment())
- {
- LLDrawable* rootparent = root->getParent();
- if (rootparent) // this IS sometimes NULL
- {
- LLViewerObject *vobj = rootparent->getVObj();
- llassert(vobj); // trying to catch a bad assumption
- if (vobj) // this test may not be needed, see above
- {
- const LLVOAvatar* av = vobj->asAvatar();
- if (av && av->isImpostor())
- {
- return;
- }
- }
- }
- }
- sCull->pushBridge((LLSpatialBridge*) drawablep);
- }
- else
- {
- sCull->pushDrawable(drawablep);
- }
-
- drawablep->setVisible(camera);
- }
-}
-
-void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
-{
- LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
-
- if (!drawablep)
- {
- //llerrs << "Sending null drawable to moved list!" << llendl;
- return;
- }
-
- if (drawablep->isDead())
- {
- llwarns << "Marking NULL or dead drawable moved!" << llendl;
- return;
- }
-
- if (drawablep->getParent())
- {
- //ensure that parent drawables are moved first
- markMoved(drawablep->getParent(), damped_motion);
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- if (drawablep->isSpatialBridge())
- {
- mMovedBridge.push_back(drawablep);
- }
- else
- {
- mMovedList.push_back(drawablep);
- }
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
- if (damped_motion == FALSE)
- {
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
- }
- else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
- {
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- }
-}
-
-void LLPipeline::markShift(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
-
- if (!drawablep || drawablep->isDead())
- {
- return;
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
- {
- drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
- if (drawablep->getParent())
- {
- markShift(drawablep->getParent());
- }
- mShiftList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_SHIFT_LIST);
- }
-}
-
-void LLPipeline::shiftObjects(const LLVector3 &offset)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
-
- assertInitialized();
-
- glClear(GL_DEPTH_BUFFER_BIT);
- gDepthDirty = TRUE;
-
- LLVector4a offseta;
- offseta.load3(offset.mV);
-
- for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
- iter != mShiftList.end(); iter++)
- {
- LLDrawable *drawablep = *iter;
- if (drawablep->isDead())
- {
- continue;
- }
- drawablep->shiftPos(offseta);
- drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
- }
- mShiftList.resize(0);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->shift(offseta);
- }
- }
- }
-
- LLHUDText::shiftAll(offset);
- LLHUDNameTag::shiftAll(offset);
- display_update_camera();
-}
-
-void LLPipeline::markTextured(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- mRetexturedList.insert(drawablep);
- }
-}
-
-void LLPipeline::markGLRebuild(LLGLUpdate* glu)
-{
- if (glu && !glu->mInQ)
- {
- LLGLUpdate::sGLQ.push_back(glu);
- glu->mInQ = TRUE;
- }
-}
-
-void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- if (group && !group->isDead() && group->mSpatialPartition)
- {
- if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
- {
- priority = TRUE;
- }
-
- if (priority)
- {
- if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
- {
- llassert_always(!mGroupQ1Locked);
-
- mGroupQ1.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q1);
-
- if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
- {
- LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
- if (iter != mGroupQ2.end())
- {
- mGroupQ2.erase(iter);
- }
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
- }
- }
- }
- else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
- {
- llassert_always(!mGroupQ2Locked);
- mGroupQ2.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q2);
-
- }
- }
-}
-
-void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- if (!drawablep->isState(LLDrawable::BUILT))
- {
- priority = TRUE;
- }
- if (priority)
- {
- if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
- {
- mBuildQ1.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
- }
- }
- else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- mBuildQ2.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
- }
- if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
- {
- drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
- }
- drawablep->setState(flag);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
-
-void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
-{
- if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::END_RENDER_TYPES))
- {
- //clear faces from face pools
- LLFastTimer t(FTM_RESET_DRAWORDER);
- gPipeline.resetDrawOrders();
- }
-
- LLFastTimer ftm(FTM_STATESORT);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- //LLVertexBuffer::unbind();
-
- grabReferences(result);
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- markVisible(*i, camera);
- }
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- LLSpatialGroup* last_group = NULL;
- for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLCullResult::bridge_list_t::iterator cur_iter = i;
- LLSpatialBridge* bridge = *cur_iter;
- LLSpatialGroup* group = bridge->getSpatialGroup();
-
- if (last_group == NULL)
- {
- last_group = group;
- }
-
- if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- stateSort(bridge, camera);
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- last_group != group && last_group->changeLOD())
- {
- last_group->mLastUpdateDistance = last_group->mDistance;
- }
-
- last_group = group;
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- last_group && last_group->changeLOD())
- {
- last_group->mLastUpdateDistance = last_group->mDistance;
- }
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- stateSort(group, camera);
- }
- }
-
- {
- LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
- iter != sCull->endVisibleList(); ++iter)
- {
- LLDrawable *drawablep = *iter;
- if (!drawablep->isDead())
- {
- stateSort(drawablep, camera);
- }
- }
- }
- {
- LLFastTimer ftm(FTM_CLIENT_COPY);
- LLVertexBuffer::clientCopy();
- }
-
- postSort(camera);
-}
-
-void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (group->changeLOD())
- {
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- LLDrawable* drawablep = *i;
- stateSort(drawablep, camera);
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- { //avoid redundant stateSort calls
- group->mLastUpdateDistance = group->mDistance;
- }
- }
-
-}
-
-void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (bridge->getSpatialGroup()->changeLOD())
- {
- bool force_update = false;
- bridge->updateDistance(camera, force_update);
- }
-}
-
-void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- if (!drawablep
- || drawablep->isDead()
- || !hasRenderType(drawablep->getRenderType()))
- {
- return;
- }
-
- if (LLSelectMgr::getInstance()->mHideSelectedObjects)
- {
- if (drawablep->getVObj().notNull() &&
- drawablep->getVObj()->isSelected())
- {
- return;
- }
- }
-
- if (drawablep->isAvatar())
- { //don't draw avatars beyond render distance or if we don't have a spatial group.
- if ((drawablep->getSpatialGroup() == NULL) ||
- (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
- {
- return;
- }
-
- LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
- if (!avatarp->isVisible())
- {
- return;
- }
- }
-
- assertInitialized();
-
- if (hasRenderType(drawablep->mRenderType))
- {
- if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
- {
- drawablep->setVisible(camera, NULL, FALSE);
- }
- else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
- {
- // clear invisible flag here to avoid single frame glitch
- drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
- {
- if (!drawablep->isActive())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update);
- }
- else if (drawablep->isAvatar())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
- }
- }
- }
-
- if (!drawablep->getVOVolume())
- {
- for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
- iter != drawablep->mFaces.end(); iter++)
- {
- LLFace* facep = *iter;
-
- if (facep->hasGeometry())
- {
- if (facep->getPool())
- {
- facep->getPool()->enqueue(facep);
- }
- else
- {
- break;
- }
- }
- }
- }
-
-
- mNumVisibleFaces += drawablep->getNumFaces();
-}
-
-
-void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
- LLCullResult::sg_list_t::iterator end,
- void (*func)(LLDrawable*))
-{
- for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
- {
- for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
- {
- func(*j);
- }
- }
-}
-
-void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
-{
- forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
- forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
-}
-
-//function for creating scripted beacons
-void renderScriptedBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderScriptedTouchBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted()
- && vobj->flagHandleTouch())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderPhysicalBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- //&& !vobj->getParent()
- && vobj->usePhysics())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderMOAPBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
-
- if(!vobj || vobj->isAvatar())
- return;
-
- BOOL beacon=FALSE;
- U8 tecount=vobj->getNumTEs();
- for(int x=0;x<tecount;x++)
- {
- if(vobj->getTE(x)->hasMedia())
- {
- beacon=TRUE;
- break;
- }
- }
- if(beacon==TRUE)
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderParticleBeacons(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && vobj->isParticleSource())
- {
- if (gPipeline.sRenderBeacons)
- {
- LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderSoundHighlights(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj && vobj->isAudioSource())
- {
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void LLPipeline::postSort(LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
- LLFastTimer ftm(FTM_STATESORT_POSTSORT);
-
- assertInitialized();
-
- llpushcallstacks ;
- //rebuild drawable geometry
- for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!sUseOcclusion ||
- !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- group->rebuildGeom();
- }
- }
- llpushcallstacks ;
- //rebuild groups
- sCull->assertDrawMapsEmpty();
-
- rebuildPriorityGroups();
- llpushcallstacks ;
-
- const S32 bin_count = 1024*8;
-
- static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
- static U32 bin_size[bin_count];
-
- //clear one bin per frame to avoid memory bloat
- static S32 clear_idx = 0;
- clear_idx = (1+clear_idx)%bin_count;
- alpha_bins[clear_idx].clear();
-
- for (U32 j = 0; j < bin_count; j++)
- {
- bin_size[j] = 0;
- }
-
- //build render map
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (sUseOcclusion &&
- group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- continue;
- }
-
- if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
- { //no way this group is going to be drawable without a rebuild
- group->rebuildGeom();
- }
-
- for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
- {
- LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
- if (!hasRenderType(j->first))
- {
- continue;
- }
-
- for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
- {
- if (sMinRenderSize > 0.f)
- {
- LLVector4a bounds;
- bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
-
- if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- else
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
- {
- LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
-
- if (alpha != group->mDrawMap.end())
- { //store alpha groups for sorting
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- if (bridge)
- {
- LLCamera trans_camera = bridge->transformCamera(camera);
- group->updateDistance(trans_camera);
- }
- else
- {
- group->updateDistance(camera);
- }
- }
-
- if (hasRenderType(LLDrawPool::POOL_ALPHA))
- {
- sCull->pushAlphaGroup(group);
- }
- }
- }
- }
-
- if (!sShadowRender)
- {
- //sort by texture or bump map
- for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
- {
- if (i == LLRenderPass::PASS_BUMP)
- {
- std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
- }
- else
- {
- std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
- }
- }
-
- std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
- }
- llpushcallstacks ;
- // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
- if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
- {
- if (sRenderScriptedTouchBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedTouchBeacons);
- }
- else
- if (sRenderScriptedBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedBeacons);
- }
-
- if (sRenderPhysicalBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderPhysicalBeacons);
- }
-
- if(sRenderMOAPBeacons)
- {
- forAllVisibleDrawables(renderMOAPBeacons);
- }
-
- if (sRenderParticleBeacons)
- {
- forAllVisibleDrawables(renderParticleBeacons);
- }
-
- // If god mode, also show audio cues
- if (sRenderSoundBeacons && gAudiop)
- {
- // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
- LLAudioEngine::source_map::iterator iter;
- for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
- {
- LLAudioSource *sourcep = iter->second;
-
- LLVector3d pos_global = sourcep->getPositionGlobal();
- LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
- if (gPipeline.sRenderBeacons)
- {
- //pos += LLVector3(0.f, 0.f, 0.2f);
- gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
- }
- // now deal with highlights for all those seeable sound sources
- forAllVisibleDrawables(renderSoundHighlights);
- }
- }
- llpushcallstacks ;
- // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
- if (LLFloaterTelehub::renderBeacons())
- {
- LLFloaterTelehub::addBeacons();
- }
-
- if (!sShadowRender)
- {
- mSelectedFaces.clear();
-
- // Draw face highlights for selected faces.
- if (LLSelectMgr::getInstance()->getTEMode())
- {
- struct f : public LLSelectedTEFunctor
- {
- virtual bool apply(LLViewerObject* object, S32 te)
- {
- if (object->mDrawable)
- {
- gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
- }
- }
-
- //LLSpatialGroup::sNoDelete = FALSE;
- llpushcallstacks ;
-}
-
-
-void render_hud_elements()
-{
- LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
- LLFastTimer t(FTM_RENDER_UI);
- gPipeline.disableLights();
-
- LLGLDisable fog(GL_FOG);
- LLGLSUIDefault gls_ui;
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
- glStencilMask(0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
- gGL.color4f(1,1,1,1);
- if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
- gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
-
- // Draw the tracking overlays
- LLTracker::render3D();
-
- // Show the property lines
- LLWorld::getInstance()->renderPropertyLines();
- LLViewerParcelMgr::getInstance()->render();
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
-
- // Render name tags.
- LLHUDObject::renderAll();
- }
- else if (gForceRenderLandFence)
- {
- // This is only set when not rendering the UI, for parcel snapshots
- LLViewerParcelMgr::getInstance()->render();
- }
- else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- LLHUDText::renderAllHUD();
- }
- gGL.flush();
-}
-
-void LLPipeline::renderHighlights()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
-
- assertInitialized();
-
- // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
- // Render highlighted faces.
- LLGLSPipelineAlpha gls_pipeline_alpha;
- LLColor4 color(1.f, 1.f, 1.f, 0.5f);
- LLGLEnable color_mat(GL_COLOR_MATERIAL);
- disableLights();
-
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
- { //draw blurry highlight image over screen
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- LLGLDisable test(GL_ALPHA_TEST);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- gGL.flush();
- glStencilMask(0xFFFFFFFF);
- glClearStencil(1);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
-
- gGL.setColorMask(false, false);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
- {
- renderHighlight(iter->mItem->getVObj(), 1.f);
- }
- gGL.setColorMask(true, false);
-
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-
- //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- gGL.pushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- gGL.pushMatrix();
- glLoadIdentity();
-
- gGL.getTexUnit(0)->bind(&mHighlight);
-
- LLVector2 tc1;
- LLVector2 tc2;
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- gGL.begin(LLRender::TRIANGLES);
-
- F32 scale = gSavedSettings.getF32("RenderHighlightBrightness");
- LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor");
- F32 thickness = gSavedSettings.getF32("RenderHighlightThickness");
-
- for (S32 pass = 0; pass < 2; ++pass)
- {
- if (pass == 0)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
- }
- else
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- for (S32 i = 0; i < 8; ++i)
- {
- for (S32 j = 0; j < 8; ++j)
- {
- LLVector2 tc(i-4+0.5f, j-4+0.5f);
-
- F32 dist = 1.f-(tc.length()/sqrtf(32.f));
- dist *= scale/64.f;
-
- tc *= thickness;
- tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
- tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
-
- gGL.color4f(color.mV[0],
- color.mV[1],
- color.mV[2],
- color.mV[3]*dist);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(3,-1);
- }
- }
- }
-
- gGL.end();
-
- gGL.popMatrix();
- glMatrixMode(GL_MODELVIEW);
- gGL.popMatrix();
-
- //gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
- {
- gHighlightProgram.bind();
- gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Make sure the selection image gets downloaded and decoded
- if (!mFaceSelectImagep)
- {
- mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
- }
- mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
-
- U32 count = mSelectedFaces.size();
- for (U32 i = 0; i < count; i++)
- {
- LLFace *facep = mSelectedFaces[i];
- if (!facep || facep->getDrawable()->isDead())
- {
- llerrs << "Bad face on selection" << llendl;
- return;
- }
-
- facep->renderSelected(mFaceSelectImagep, color);
- }
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Paint 'em red!
- color.setVec(1.f, 0.f, 0.f, 0.5f);
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
- {
- gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
- }
- int count = mHighlightFaces.size();
- for (S32 i = 0; i < count; i++)
- {
- LLFace* facep = mHighlightFaces[i];
- facep->renderSelected(LLViewerTexture::sNullImagep, color);
- }
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
- {
- gHighlightProgram.unbind();
- }
-}
-
-//debug use
-U32 LLPipeline::sCurRenderPoolType = 0 ;
-
-void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- assertInitialized();
-
- F64 saved_modelview[16];
- F64 saved_projection[16];
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- saved_modelview[i] = gGLModelView[i];
- saved_projection[i] = gGLProjection[i];
- }
- }
-
- S32 stack_depth = 0;
-
- if (gDebugGL)
- {
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth);
- }
-
- ///////////////////////////////////////////
- //
- // Sync and verify GL state
- //
- //
-
- stop_glerror();
-
- LLVertexBuffer::unbind();
-
- // Do verification of GL state
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
- {
- if (!verify())
- {
- llerrs << "Pipeline verification failed!" << llendl;
- }
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
-
- // Initialize lots of GL state to "safe" values
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
-
- LLGLSPipeline gls_pipeline;
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
-
- // Toggle backface culling for debugging
- LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
- // Set fog
- BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
- LLGLEnable fog_enable(use_fog &&
- !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
- gSky.updateFog(camera.getFar());
- if (!use_fog)
- {
- sUnderWaterRender = FALSE;
- }
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
- LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
-
- //////////////////////////////////////////////
- //
- // Actually render all of the geometry
- //
- //
- stop_glerror();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- {
- LLFastTimer t(FTM_POOLS);
-
- // HACK: don't calculate local lights if we're rendering the HUD!
- // Removing this check will cause bad flickering when there are
- // HUD elements being rendered AND the user is in flycam mode -nyx
- if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- calcNearbyLights(camera);
- setupHWLights(NULL);
- }
-
- BOOL occlude = sUseOcclusion > 1;
- U32 cur_type = 0;
-
- pool_set_t::iterator iter1 = mPools.begin();
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- //debug use
- sCurRenderPoolType = cur_type ;
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginRenderPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->render(i);
- }
- poolp->endRenderPass(i);
- LLVertexBuffer::unbind();
- if (gDebugGL)
- {
- check_stack_depth(stack_depth);
- std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
- LLGLState::checkStates(msg);
- LLGLState::checkTextureChannels(msg);
- LLGLState::checkClientArrays(msg);
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
-
- LLVertexBuffer::unbind();
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- }
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
-
-
- stop_glerror();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
-
- if (!sReflectionRender)
- {
- renderHighlights();
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
- {
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- gGLModelView[i] = saved_modelview[i];
- gGLProjection[i] = saved_projection[i];
- }
- }
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-}
-
-void LLPipeline::renderGeomDeferred(LLCamera& camera)
-{
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
-
- LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- LLFastTimer t2(FTM_POOLS);
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
- stop_glerror();
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- stop_glerror();
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- U32 cur_type = 0;
-
- gGL.setColorMask(true, true);
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderDeferred(i);
- }
- poolp->endDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- gGL.setColorMask(true, false);
-}
-
-void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
-{
- LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
- LLFastTimer t(FTM_POOLS);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- calcNearbyLights(camera);
- setupHWLights(NULL);
-
- gGL.setColorMask(true, false);
-
- pool_set_t::iterator iter1 = mPools.begin();
- BOOL occlude = LLPipeline::sUseOcclusion > 1;
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- gGL.setColorMask(true, false);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginPostDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderPostDeferred(i);
- }
- poolp->endPostDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- }
-}
-
-void LLPipeline::renderGeomShadow(LLCamera& camera)
-{
- LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLVertexBuffer::unbind();
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
- {
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginShadowPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderShadow(i);
- }
- poolp->endShadowPass(i);
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-}
-
-
-void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
-{
- assertInitialized();
- S32 count = 0;
- if (render_type == LLRender::TRIANGLE_STRIP)
- {
- count = index_count-2;
- }
- else
- {
- count = index_count/3;
- }
-
- mTrianglesDrawn += count;
- mBatchCount++;
- mMaxBatchSize = llmax(mMaxBatchSize, count);
- mMinBatchSize = llmin(mMinBatchSize, count);
-
- if (LLPipeline::sRenderFrameTest)
- {
- gViewerWindow->getWindow()->swapBuffers();
- ms_sleep(16);
- }
-}
-
-void LLPipeline::renderPhysicsDisplay()
-{
- if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
- {
- return;
- }
-
- allocatePhysicsBuffer();
-
- gGL.flush();
- mPhysicsDisplay.bindTarget();
- glClearColor(0,0,0,1);
- gGL.setColorMask(true, true);
- mPhysicsDisplay.clear();
- glClearColor(0,0,0,0);
-
- gGL.setColorMask(true, false);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderPhysicsShapes();
- }
- }
- }
- }
-
- for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
- {
- glPushMatrix();
- glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- bridge->renderPhysicsShapes();
- glPopMatrix();
- }
- }
-
-
- gGL.flush();
- mPhysicsDisplay.flush();
-}
-
-
-void LLPipeline::renderDebug()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- gGL.color4f(1,1,1,1);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- gGL.setColorMask(true, false);
-
- bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD);
-
- // Debug stuff.
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
- !hud_only && hasRenderType(part->mDrawableType) )
- {
- part->renderDebug();
- }
- }
- }
- }
-
- for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
- {
- glPushMatrix();
- glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- bridge->renderDebug();
- glPopMatrix();
- }
- }
-
- if (gSavedSettings.getBOOL("DebugShowUploadCost"))
- {
- std::set<LLUUID> textures;
- std::set<LLUUID> sculpts;
- std::set<LLUUID> meshes;
-
- BOOL selected = TRUE;
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- selected = FALSE;
- }
-
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
- for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem)
- {
- LLDrawable* drawable = *elem;
- LLVOVolume* volume = drawable->getVOVolume();
- if (volume && volume->isSelected() == selected)
- {
- for (U32 i = 0; i < volume->getNumTEs(); ++i)
- {
- LLTextureEntry* te = volume->getTE(i);
- textures.insert(te->getID());
- }
-
- if (volume->isSculpted())
- {
- LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID();
- if (volume->isMesh())
- {
- meshes.insert(sculpt_id);
- }
- else
- {
- sculpts.insert(sculpt_id);
- }
- }
- }
- }
- }
-
- gPipeline.mDebugTextureUploadCost = textures.size() * 10;
- gPipeline.mDebugSculptUploadCost = sculpts.size()*10;
-
- U32 mesh_cost = 0;
-
- for (std::set<LLUUID>::iterator iter = meshes.begin(); iter != meshes.end(); ++iter)
- {
- mesh_cost += gMeshRepo.getResourceCost(*iter)*10;
- }
-
- gPipeline.mDebugMeshUploadCost = mesh_cost;
- }
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLVertexBuffer::unbind();
-
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(TRUE, FALSE);
- LLGLDisable cull(GL_CULL_FACE);
-
- gGL.color4f(1,1,1,1);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- F32 a = 0.1f;
-
- F32 col[] =
- {
- 1,0,0,a,
- 0,1,0,a,
- 0,0,1,a,
- 1,0,1,a,
-
- 1,1,0,a,
- 0,1,1,a,
- 1,1,1,a,
- 1,0,1,a,
- };
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector3* frust = mShadowCamera[i].mAgentFrustum;
-
- if (i > 3)
- { //render shadow frusta as volumes
- if (mShadowFrustPoints[i-4].empty())
- {
- continue;
- }
-
- gGL.color4fv(col+(i-4)*4);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.end();
-
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[2].mV);
- gGL.end();
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[6].mV);
- gGL.end();
- }
-
-
- if (i < 4)
- {
-
- //if (i == 0 || !mShadowFrustPoints[i].empty())
- {
- //render visible point cloud
- gGL.flush();
- glPointSize(8.f);
- gGL.begin(LLRender::POINTS);
-
- F32* c = col+i*4;
- gGL.color3fv(c);
-
- for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
- {
- gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
-
- }
- gGL.end();
-
- gGL.flush();
- glPointSize(1.f);
-
- LLVector3* ext = mShadowExtents[i];
- LLVector3 pos = (ext[0]+ext[1])*0.5f;
- LLVector3 size = (ext[1]-ext[0])*0.5f;
- drawBoxOutline(pos, size);
-
- //render camera frustum splits as outlines
- gGL.begin(LLRender::LINES);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.end();
- }
- }
-
- /*gGL.flush();
- glLineWidth(16-i*2);
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderIntersectingBBoxes(&mShadowCamera[i]);
- }
- }
- }
- }
- gGL.flush();
- glLineWidth(1.f);*/
- }
- }
-
- if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
- {
- // Debug composition layers
- F32 x, y;
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- if (gAgent.getRegion())
- {
- gGL.begin(LLRender::POINTS);
- // Draw the composition layer for the region that I'm in.
- for (x = 0; x <= 260; x++)
- {
- for (y = 0; y <= 260; y++)
- {
- if ((x > 255) || (y > 255))
- {
- gGL.color4f(1.f, 0.f, 0.f, 1.f);
- }
- else
- {
- gGL.color4f(0.f, 0.f, 1.f, 1.f);
- }
- F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
- z *= 5.f;
- z += 50.f;
- gGL.vertex3f(x, y, z);
- }
- }
- gGL.end();
- }
- }
-
- if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
- {
- U32 count = 0;
- U32 size = mGroupQ2.size();
- LLColor4 col;
-
- LLVertexBuffer::unbind();
- LLGLEnable blend(GL_BLEND);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-
- gGL.pushMatrix();
- glLoadMatrixd(gGLModelView);
- gGLLastMatrix = NULL;
-
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- if (group->isDead())
- {
- continue;
- }
-
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
-
- if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
- {
- continue;
- }
-
- if (bridge)
- {
- gGL.pushMatrix();
- glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- }
-
- F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f);
-
-
- LLVector2 c(1.f-alpha, alpha);
- c.normVec();
-
-
- ++count;
- col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f);
- group->drawObjectBox(col);
-
- if (bridge)
- {
- gGL.popMatrix();
- }
- }
-
- gGL.popMatrix();
- }
-
- gGL.flush();
-
- gPipeline.renderPhysicsDisplay();
-}
-
-void LLPipeline::rebuildPools()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
-
- assertInitialized();
-
- S32 max_count = mPools.size();
- pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
- while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
- {
- if (iter1 == mPools.end())
- {
- iter1 = mPools.begin();
- }
- LLDrawPool* poolp = *iter1;
-
- if (poolp->isDead())
- {
- mPools.erase(iter1++);
- removeFromQuickLookup( poolp );
- if (poolp == mLastRebuildPool)
- {
- mLastRebuildPool = NULL;
- }
- delete poolp;
- }
- else
- {
- mLastRebuildPool = poolp;
- iter1++;
- }
- max_count--;
- }
-
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->rebuildHUD();
- }
-}
-
-void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
-
- assertInitialized();
-
- switch( new_poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- if (mSimplePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mSimplePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GRASS:
- if (mGrassPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate grass pool." << llendl;
- }
- else
- {
- mGrassPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- if (mFullbrightPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mFullbrightPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- if (mInvisiblePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mInvisiblePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GLOW:
- if (mGlowPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate glow pool." << llendl;
- }
- else
- {
- mGlowPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_TREE:
- mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_BUMP:
- if (mBumpPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate bump pool." << llendl;
- }
- else
- {
- mBumpPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_ALPHA:
- if( mAlphaPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
- }
- else
- {
- mAlphaPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- if( mSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
- }
- else
- {
- mSkyPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WATER:
- if( mWaterPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
- }
- else
- {
- mWaterPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GROUND:
- if( mGroundPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
- }
- else
- {
- mGroundPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- if( mWLSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
- }
- else
- {
- mWLSkyPool = new_poolp;
- }
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
- break;
- }
-}
-
-void LLPipeline::removePool( LLDrawPool* poolp )
-{
- assertInitialized();
- removeFromQuickLookup(poolp);
- mPools.erase(poolp);
- delete poolp;
-}
-
-void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
-{
- assertInitialized();
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- switch( poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- llassert(mSimplePool == poolp);
- mSimplePool = NULL;
- break;
-
- case LLDrawPool::POOL_GRASS:
- llassert(mGrassPool == poolp);
- mGrassPool = NULL;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- llassert(mFullbrightPool == poolp);
- mFullbrightPool = NULL;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- llassert(mInvisiblePool == poolp);
- mInvisiblePool = NULL;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- llassert(mWLSkyPool == poolp);
- mWLSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_GLOW:
- llassert(mGlowPool == poolp);
- mGlowPool = NULL;
- break;
-
- case LLDrawPool::POOL_TREE:
- #ifdef _DEBUG
- {
- BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTreePools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- #ifdef _DEBUG
- {
- BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_BUMP:
- llassert( poolp == mBumpPool );
- mBumpPool = NULL;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- llassert( poolp == mAlphaPool );
- mAlphaPool = NULL;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- llassert( poolp == mSkyPool );
- mSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_WATER:
- llassert( poolp == mWaterPool );
- mWaterPool = NULL;
- break;
-
- case LLDrawPool::POOL_GROUND:
- llassert( poolp == mGroundPool );
- mGroundPool = NULL;
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
- break;
- }
-}
-
-void LLPipeline::resetDrawOrders()
-{
- assertInitialized();
- // Iterate through all of the draw pools and rebuild them.
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- poolp->resetDrawOrders();
- }
-}
-
-//============================================================================
-// Once-per-frame setup of hardware lights,
-// including sun/moon, avatar backlight, and up to 6 local lights
-
-void LLPipeline::setupAvatarLights(BOOL for_edit)
-{
- assertInitialized();
-
- if (for_edit)
- {
- LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
- LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
- LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
- LLMatrix4 camera_rot(camera_mat.getMat3());
- camera_rot.invert();
- LLVector4 light_pos = light_pos_cam * camera_rot;
-
- light_pos.normalize();
-
- LLLightState* light = gGL.getLight(1);
-
- mHWLightColors[1] = diffuse;
-
- light->setDiffuse(diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setPosition(light_pos);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
- else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
- {
- LLVector3 opposite_pos = -1.f * mSunDir;
- LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
- LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
- backlight_pos.normalize();
-
- LLColor4 light_diffuse = mSunDiffuse;
- LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
- F32 max_component = 0.001f;
- for (S32 i = 0; i < 3; i++)
- {
- if (backlight_diffuse.mV[i] > max_component)
- {
- max_component = backlight_diffuse.mV[i];
- }
- }
- F32 backlight_mag;
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
- }
- else
- {
- backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
- }
- backlight_diffuse *= backlight_mag / max_component;
-
- mHWLightColors[1] = backlight_diffuse;
-
- LLLightState* light = gGL.getLight(1);
-
- light->setPosition(backlight_pos);
- light->setDiffuse(backlight_diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
- else
- {
- LLLightState* light = gGL.getLight(1);
-
- mHWLightColors[1] = LLColor4::black;
-
- light->setDiffuse(LLColor4::black);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- }
-}
-
-static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
-{
- F32 inten = light->getLightIntensity();
- if (inten < .001f)
- {
- return max_dist;
- }
- F32 radius = light->getLightRadius();
- BOOL selected = light->isSelected();
- LLVector3 dpos = light->getRenderPosition() - cam_pos;
- F32 dist2 = dpos.lengthSquared();
- if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
- {
- return max_dist;
- }
- F32 dist = (F32) sqrt(dist2);
- dist *= 1.f / inten;
- dist -= radius;
- if (selected)
- {
- dist -= 10000.f; // selected lights get highest priority
- }
- if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
- {
- // moving lights get a little higher priority (too much causes artifacts)
- dist -= light->getLightRadius()*0.25f;
- }
- return dist;
-}
-
-void LLPipeline::calcNearbyLights(LLCamera& camera)
-{
- assertInitialized();
-
- if (LLPipeline::sReflectionRender)
- {
- return;
- }
-
- if (mLightingDetail >= 1)
- {
- // mNearbyLight (and all light_set_t's) are sorted such that
- // begin() == the closest light and rbegin() == the farthest light
- const S32 MAX_LOCAL_LIGHTS = 6;
-// LLVector3 cam_pos = gAgent.getCameraPositionAgent();
- LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
- camera.getOrigin() :
- gAgent.getPositionAgent();
-
- F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
-
- // UPDATE THE EXISTING NEARBY LIGHTS
- light_set_t cur_nearby_lights;
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- const Light* light = &(*iter);
- LLDrawable* drawable = light->drawable;
- LLVOVolume* volight = drawable->getVOVolume();
- if (!volight || !drawable->isState(LLDrawable::LIGHT))
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (light->fade <= -LIGHT_FADE_TIME)
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (!sRenderAttachedLights && volight && volight->isAttachment())
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
-
- F32 dist = calc_light_dist(volight, cam_pos, max_dist);
- cur_nearby_lights.insert(Light(drawable, dist, light->fade));
- }
- mNearbyLights = cur_nearby_lights;
-
- // FIND NEW LIGHTS THAT ARE IN RANGE
- light_set_t new_nearby_lights;
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
- iter != mLights.end(); ++iter)
- {
- LLDrawable* drawable = *iter;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
- {
- continue;
- }
- if (light->isHUDAttachment())
- {
- continue; // no lighting from HUD objects
- }
- F32 dist = calc_light_dist(light, cam_pos, max_dist);
- if (dist >= max_dist)
- {
- continue;
- }
- if (!sRenderAttachedLights && light && light->isAttachment())
- {
- continue;
- }
- new_nearby_lights.insert(Light(drawable, dist, 0.f));
- if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
- {
- new_nearby_lights.erase(--new_nearby_lights.end());
- const Light& last = *new_nearby_lights.rbegin();
- max_dist = last.dist;
- }
- }
-
- // INSERT ANY NEW LIGHTS
- for (light_set_t::iterator iter = new_nearby_lights.begin();
- iter != new_nearby_lights.end(); iter++)
- {
- const Light* light = &(*iter);
- if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
- {
- mNearbyLights.insert(*light);
- ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
- }
- else
- {
- // crazy cast so that we can overwrite the fade value
- // even though gcc enforces sets as const
- // (fade value doesn't affect sort so this is safe)
- Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
- if (light->dist < farthest_light->dist)
- {
- if (farthest_light->fade >= 0.f)
- {
- farthest_light->fade = -gFrameIntervalSeconds;
- }
- }
- else
- {
- break; // none of the other lights are closer
- }
- }
- }
-
- }
-}
-
-void LLPipeline::setupHWLights(LLDrawPool* pool)
-{
- assertInitialized();
-
- // Ambient
- LLColor4 ambient = gSky.getTotalAmbientColor();
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
-
- // Light 0 = Sun or Moon (All objects)
- {
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- mSunDir.setVec(gSky.getSunDirection());
- mSunDiffuse.setVec(gSky.getSunDiffuseColor());
- }
- else
- {
- mSunDir.setVec(gSky.getMoonDirection());
- mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
- }
-
- F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
- if (max_color > 1.f)
- {
- mSunDiffuse *= 1.f/max_color;
- }
- mSunDiffuse.clamp();
-
- LLVector4 light_pos(mSunDir, 0.0f);
- LLColor4 light_diffuse = mSunDiffuse;
- mHWLightColors[0] = light_diffuse;
-
- LLLightState* light = gGL.getLight(0);
- light->setPosition(light_pos);
- light->setDiffuse(light_diffuse);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setConstantAttenuation(1.f);
- light->setLinearAttenuation(0.f);
- light->setQuadraticAttenuation(0.f);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
-
- // Light 1 = Backlight (for avatars)
- // (set by enableLightsAvatar)
-
- S32 cur_light = 2;
-
- // Nearby lights = LIGHT 2-7
-
- mLightMovingMask = 0;
-
- if (mLightingDetail >= 1)
- {
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); ++iter)
- {
- LLDrawable* drawable = iter->drawable;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light)
- {
- continue;
- }
- if (drawable->isState(LLDrawable::ACTIVE))
- {
- mLightMovingMask |= (1<<cur_light);
- }
-
- LLColor4 light_color = light->getLightColor();
- light_color.mV[3] = 0.0f;
-
- F32 fade = iter->fade;
- if (fade < LIGHT_FADE_TIME)
- {
- // fade in/out light
- if (fade >= 0.f)
- {
- fade = fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
- }
- else
- {
- fade = 1.f + fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
- }
- fade = llclamp(fade,0.f,1.f);
- light_color *= fade;
- }
-
- LLVector3 light_pos(light->getRenderPosition());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-
- F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[cur_light] = light_color;
- LLLightState* light_state = gGL.getLight(cur_light);
-
- light_state->setPosition(light_pos_gl);
- light_state->setDiffuse(light_color);
- light_state->setAmbient(LLColor4::black);
- light_state->setConstantAttenuation(0.f);
- light_state->setLinearAttenuation(linatten);
- light_state->setQuadraticAttenuation(0.f);
-
- if (light->isLightSpotlight() // directional (spot-)light
- && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
- {
- LLVector3 spotparams = light->getSpotLightParams();
- LLQuaternion quat = light->getRenderRotation();
- LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
- at_axis *= quat;
-
- light_state->setSpotDirection(at_axis);
- light_state->setSpotCutoff(90.f);
- light_state->setSpotExponent(2.f);
-
- light_state->setSpecular(LLColor4::black);
- }
- else // omnidirectional (point) light
- {
- light_state->setSpotExponent(0.f);
- light_state->setSpotCutoff(180.f);
-
- // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
- const LLColor4 specular(0.f, 0.f, 0.f, 1.f);
- light_state->setSpecular(specular);
- }
- cur_light++;
- if (cur_light >= 8)
- {
- break; // safety
- }
- }
- }
- for ( ; cur_light < 8 ; cur_light++)
- {
- mHWLightColors[cur_light] = LLColor4::black;
- LLLightState* light = gGL.getLight(cur_light);
-
- light->setDiffuse(LLColor4::black);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- }
- if (gAgentAvatarp &&
- gAgentAvatarp->mSpecialRenderMode == 3)
- {
- LLColor4 light_color = LLColor4::white;
- light_color.mV[3] = 0.0f;
-
- LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = 16.f;
-
- F32 x = 3.f;
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[2] = light_color;
- LLLightState* light = gGL.getLight(2);
-
- light->setPosition(light_pos_gl);
- light->setDiffuse(light_color);
- light->setAmbient(LLColor4::black);
- light->setSpecular(LLColor4::black);
- light->setQuadraticAttenuation(0.f);
- light->setConstantAttenuation(0.f);
- light->setLinearAttenuation(linatten);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
- }
-
- // Init GL state
- glDisable(GL_LIGHTING);
- for (S32 i = 0; i < 8; ++i)
- {
- gGL.getLight(i)->disable();
- }
- mLightMask = 0;
-}
-
-void LLPipeline::enableLights(U32 mask)
-{
- assertInitialized();
-
- if (mLightingDetail == 0)
- {
- mask &= 0xf003; // sun and backlight only (and fullbright bit)
- }
- if (mLightMask != mask)
- {
- stop_glerror();
- if (!mLightMask)
- {
- glEnable(GL_LIGHTING);
- }
- if (mask)
- {
- stop_glerror();
- for (S32 i=0; i<8; i++)
- {
- LLLightState* light = gGL.getLight(i);
- if (mask & (1<<i))
- {
- light->enable();
- light->setDiffuse(mHWLightColors[i]);
- }
- else
- {
- light->disable();
- light->setDiffuse(LLColor4::black);
- }
- }
- stop_glerror();
- }
- else
- {
- glDisable(GL_LIGHTING);
- }
- stop_glerror();
- mLightMask = mask;
- LLColor4 ambient = gSky.getTotalAmbientColor();
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
- stop_glerror();
- }
-}
-
-void LLPipeline::enableLightsStatic()
-{
- assertInitialized();
- U32 mask = 0x01; // Sun
- if (mLightingDetail >= 2)
- {
- mask |= mLightMovingMask; // Hardware moving lights
- }
- else
- {
- mask |= 0xff & (~2); // Hardware local lights
- }
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsDynamic()
-{
- assertInitialized();
- U32 mask = 0xff & (~2); // Local lights
- enableLights(mask);
-
- if (isAgentAvatarValid() && getLightingDetail() <= 0)
- {
- if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
- {
- gPipeline.enableLightsAvatar();
- }
- else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
- {
- gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
- }
- }
-}
-
-void LLPipeline::enableLightsAvatar()
-{
- U32 mask = 0xff; // All lights
- setupAvatarLights(FALSE);
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsPreview()
-{
- disableLights();
-
- glEnable(GL_LIGHTING);
- LLColor4 ambient = gSavedSettings.getColor4("PreviewAmbientColor");
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
-
-
- LLColor4 diffuse0 = gSavedSettings.getColor4("PreviewDiffuse0");
- LLColor4 specular0 = gSavedSettings.getColor4("PreviewSpecular0");
- LLColor4 diffuse1 = gSavedSettings.getColor4("PreviewDiffuse1");
- LLColor4 specular1 = gSavedSettings.getColor4("PreviewSpecular1");
- LLColor4 diffuse2 = gSavedSettings.getColor4("PreviewDiffuse2");
- LLColor4 specular2 = gSavedSettings.getColor4("PreviewSpecular2");
-
- LLVector3 dir0 = gSavedSettings.getVector3("PreviewDirection0");
- LLVector3 dir1 = gSavedSettings.getVector3("PreviewDirection1");
- LLVector3 dir2 = gSavedSettings.getVector3("PreviewDirection2");
-
- dir0.normVec();
- dir1.normVec();
- dir2.normVec();
-
- LLVector4 light_pos(dir0, 0.0f);
-
- LLLightState* light = gGL.getLight(0);
-
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse0);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular0);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-
- light_pos = LLVector4(dir1, 0.f);
-
- light = gGL.getLight(1);
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse1);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular1);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-
- light_pos = LLVector4(dir2, 0.f);
- light = gGL.getLight(2);
- light->enable();
- light->setPosition(light_pos);
- light->setDiffuse(diffuse2);
- light->setAmbient(LLColor4::black);
- light->setSpecular(specular2);
- light->setSpotExponent(0.f);
- light->setSpotCutoff(180.f);
-}
-
-
-void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
-{
- U32 mask = 0x2002; // Avatar backlight only, set ambient
- setupAvatarLights(TRUE);
- enableLights(mask);
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
-}
-
-void LLPipeline::enableLightsFullbright(const LLColor4& color)
-{
- assertInitialized();
- U32 mask = 0x1000; // Non-0 mask, set ambient
- enableLights(mask);
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
-}
-
-void LLPipeline::disableLights()
-{
- enableLights(0); // no lighting (full bright)
-}
-
-//============================================================================
-
-class LLMenuItemGL;
-class LLInvFVBridge;
-struct cat_folder_pair;
-class LLVOBranch;
-class LLVOLeaf;
-
-void LLPipeline::findReferences(LLDrawable *drawablep)
-{
- assertInitialized();
- if (mLights.find(drawablep) != mLights.end())
- {
- llinfos << "In mLights" << llendl;
- }
- if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
- {
- llinfos << "In mMovedList" << llendl;
- }
- if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
- {
- llinfos << "In mShiftList" << llendl;
- }
- if (mRetexturedList.find(drawablep) != mRetexturedList.end())
- {
- llinfos << "In mRetexturedList" << llendl;
- }
-
- if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
- {
- llinfos << "In mBuildQ1" << llendl;
- }
- if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
- {
- llinfos << "In mBuildQ2" << llendl;
- }
-
- S32 count;
-
- count = gObjectList.findReferences(drawablep);
- if (count)
- {
- llinfos << "In other drawables: " << count << " references" << llendl;
- }
-}
-
-BOOL LLPipeline::verify()
-{
- BOOL ok = assertInitialized();
- if (ok)
- {
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (!poolp->verify())
- {
- ok = FALSE;
- }
- }
- }
-
- if (!ok)
- {
- llwarns << "Pipeline verify failed!" << llendl;
- }
- return ok;
-}
-
-//////////////////////////////
-//
-// Collision detection
-//
-//
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A method to compute a ray-AABB intersection.
- * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
- * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
- * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
- *
- * Hence this version is faster as well as more robust than the original one.
- *
- * Should work provided:
- * 1) the integer representation of 0.0f is 0x00000000
- * 2) the sign bit of the float is the most significant one
- *
- * Report bugs: p.terdiman@codercorner.com
- *
- * \param aabb [in] the axis-aligned bounding box
- * \param origin [in] ray origin
- * \param dir [in] ray direction
- * \param coord [out] impact coordinates
- * \return true if ray intersects AABB
- */
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//#define RAYAABB_EPSILON 0.00001f
-#define IR(x) ((U32&)x)
-
-bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
-{
- BOOL Inside = TRUE;
- LLVector3 MinB = center - size;
- LLVector3 MaxB = center + size;
- LLVector3 MaxT;
- MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
-
- // Find candidate planes.
- for(U32 i=0;i<3;i++)
- {
- if(origin.mV[i] < MinB.mV[i])
- {
- coord.mV[i] = MinB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- else if(origin.mV[i] > MaxB.mV[i])
- {
- coord.mV[i] = MaxB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- }
-
- // Ray origin inside bounding box
- if(Inside)
- {
- coord = origin;
- return true;
- }
-
- // Get largest of the maxT's for final choice of intersection
- U32 WhichPlane = 0;
- if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
- if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
-
- // Check final candidate actually inside box
- if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
-
- for(U32 i=0;i<3;i++)
- {
- if(i!=WhichPlane)
- {
- coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
- if (epsilon > 0)
- {
- if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
- }
- else
- {
- if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
- }
- }
- }
- return true; // ray hits box
-}
-
-//////////////////////////////
-//
-// Macros, functions, and inline methods from other classes
-//
-//
-
-void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
-{
- if (drawablep && assertInitialized())
- {
- if (is_light)
- {
- mLights.insert(drawablep);
- drawablep->setState(LLDrawable::LIGHT);
- }
- else
- {
- drawablep->clearState(LLDrawable::LIGHT);
- mLights.erase(drawablep);
- }
- }
-}
-
-//static
-void LLPipeline::toggleRenderType(U32 type)
-{
- gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
- if (type == LLPipeline::RENDER_TYPE_WATER)
- {
- gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
- }
-}
-
-//static
-void LLPipeline::toggleRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- U32 bit = (1<<type);
- if (gPipeline.hasRenderType(type))
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.toggleRenderType(type);
-}
-
-//static
-BOOL LLPipeline::hasRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- return gPipeline.hasRenderType(type);
-}
-
-// Allows UI items labeled "Hide foo" instead of "Show foo"
-//static
-BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
-{
- S32 type = (S32)(intptr_t)data;
- return !gPipeline.hasRenderType(type);
-}
-
-//static
-void LLPipeline::toggleRenderDebug(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- if (gPipeline.hasRenderDebugMask(bit))
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.mRenderDebugMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugMask(bit);
-}
-
-//static
-void LLPipeline::toggleRenderDebugFeature(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- gPipeline.mRenderDebugFeatureMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugFeatureMask(bit);
-}
-
-void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value)
-{
- if (value)
- {
- gPipeline.mRenderDebugFeatureMask |= bit;
- }
- else
- {
- gPipeline.mRenderDebugFeatureMask &= !bit;
- }
-}
-
-// static
-void LLPipeline::setRenderScriptedBeacons(BOOL val)
-{
- sRenderScriptedBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedBeacons(void*)
-{
- sRenderScriptedBeacons = !sRenderScriptedBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedBeacons(void*)
-{
- return sRenderScriptedBeacons;
-}
-
-// static
-void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
-{
- sRenderScriptedTouchBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
-{
- sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
-{
- return sRenderScriptedTouchBeacons;
-}
-
-// static
-void LLPipeline::setRenderMOAPBeacons(BOOL val)
-{
- sRenderMOAPBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderMOAPBeacons(void*)
-{
- sRenderMOAPBeacons = !sRenderMOAPBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderMOAPBeacons(void*)
-{
- return sRenderMOAPBeacons;
-}
-
-// static
-void LLPipeline::setRenderPhysicalBeacons(BOOL val)
-{
- sRenderPhysicalBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderPhysicalBeacons(void*)
-{
- sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderPhysicalBeacons(void*)
-{
- return sRenderPhysicalBeacons;
-}
-
-// static
-void LLPipeline::setRenderParticleBeacons(BOOL val)
-{
- sRenderParticleBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderParticleBeacons(void*)
-{
- sRenderParticleBeacons = !sRenderParticleBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderParticleBeacons(void*)
-{
- return sRenderParticleBeacons;
-}
-
-// static
-void LLPipeline::setRenderSoundBeacons(BOOL val)
-{
- sRenderSoundBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderSoundBeacons(void*)
-{
- sRenderSoundBeacons = !sRenderSoundBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderSoundBeacons(void*)
-{
- return sRenderSoundBeacons;
-}
-
-// static
-void LLPipeline::setRenderBeacons(BOOL val)
-{
- sRenderBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderBeacons(void*)
-{
- sRenderBeacons = !sRenderBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderBeacons(void*)
-{
- return sRenderBeacons;
-}
-
-// static
-void LLPipeline::setRenderHighlights(BOOL val)
-{
- sRenderHighlight = val;
-}
-
-// static
-void LLPipeline::toggleRenderHighlights(void*)
-{
- sRenderHighlight = !sRenderHighlight;
-}
-
-// static
-BOOL LLPipeline::getRenderHighlights(void*)
-{
- return sRenderHighlight;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- LLVector3 local_end = end;
-
- LLVector3 position;
-
- sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- if ((j == LLViewerRegion::PARTITION_VOLUME) ||
- (j == LLViewerRegion::PARTITION_BRIDGE) ||
- (j == LLViewerRegion::PARTITION_TERRAIN) ||
- (j == LLViewerRegion::PARTITION_TREE) ||
- (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- local_end = position;
- }
- }
- }
- }
- }
-
- if (!sPickAvatar)
- {
- //save hit info in case we need to restore
- //due to attachment override
- LLVector3 local_normal;
- LLVector3 local_binormal;
- LLVector2 local_texcoord;
- S32 local_face_hit = -1;
-
- if (face_hit)
- {
- local_face_hit = *face_hit;
- }
- if (tex_coord)
- {
- local_texcoord = *tex_coord;
- }
- if (bi_normal)
- {
- local_binormal = *bi_normal;
- }
- if (normal)
- {
- local_normal = *normal;
- }
-
- const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
-
- //check against avatars
- sPickAvatar = TRUE;
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- if (!drawable ||
- !drawable->getVObj()->isAttachment() ||
- (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
- { //avatar overrides if previously hit drawable is not an attachment or
- //attachment is far enough away from detected intersection
- drawable = hit;
- local_end = position;
- }
- else
- { //prioritize attachments over avatars
- position = local_end;
-
- if (face_hit)
- {
- *face_hit = local_face_hit;
- }
- if (tex_coord)
- {
- *tex_coord = local_texcoord;
- }
- if (bi_normal)
- {
- *bi_normal = local_binormal;
- }
- if (normal)
- {
- *normal = local_normal;
- }
- }
- }
- }
- }
- }
-
- //check all avatar nametags (silly, isn't it?)
- for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end();
- ++iter)
- {
- LLVOAvatar* av = (LLVOAvatar*) *iter;
- if (av->mNameText.notNull()
- && av->mNameText->lineSegmentIntersect(start, local_end, position))
- {
- drawable = av->mDrawable;
- local_end = position;
- }
- }
-
- if (intersection)
- {
- *intersection = position;
- }
-
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- BOOL toggle = FALSE;
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- toggle = TRUE;
- }
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
- if (part)
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- }
- }
-
- if (toggle)
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
- }
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
-{
- if (vobj)
- {
- LLViewerRegion* region = vobj->getRegion();
- if (region)
- {
- return region->getSpatialPartition(vobj->getPartitionType());
- }
- }
- return NULL;
-}
-
-
-void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
-{
- if (!drawable || drawable->isDead())
- {
- return;
- }
-
- for (S32 i = 0; i < drawable->getNumFaces(); i++)
- {
- LLFace* facep = drawable->getFace(i);
- facep->clearVertexBuffer();
- }
-}
-
-void LLPipeline::resetVertexBuffers()
-{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->resetVertexBuffers();
- }
- }
- }
-
- resetDrawOrders();
-
- gSky.resetVertexBuffers();
-
- if (LLVertexBuffer::sGLCount > 0)
- {
- LLVertexBuffer::cleanupClass();
- }
-
- //delete all name pool caches
- LLGLNamePool::cleanupPools();
-
- if (LLVertexBuffer::sGLCount > 0)
- {
- llwarns << "VBO wipe failed." << llendl;
- }
-
- if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() ||
- !LLVertexBuffer::sStreamVBOPool.mNameList.empty() ||
- !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() ||
- !LLVertexBuffer::sDynamicVBOPool.mNameList.empty())
- {
- llwarns << "VBO name pool cleanup failed." << llendl;
- }
-
- LLVertexBuffer::unbind();
-
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
- LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
- LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
- LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
- sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
- sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
- LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
-}
-
-void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
-{
- LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
- assertInitialized();
- glLoadMatrixd(gGLModelView);
- gGLLastMatrix = NULL;
- mSimplePool->pushBatches(type, mask);
- glLoadMatrixd(gGLModelView);
- gGLLastMatrix = NULL;
-}
-
-void apply_cube_face_rotation(U32 face)
-{
- switch (face)
- {
- case 0:
- glRotatef(90.f, 0, 1, 0);
- glRotatef(180.f, 1, 0, 0);
- break;
- case 2:
- glRotatef(-90.f, 1, 0, 0);
- break;
- case 4:
- glRotatef(180.f, 0, 1, 0);
- glRotatef(180.f, 0, 0, 1);
- break;
- case 1:
- glRotatef(-90.f, 0, 1, 0);
- glRotatef(180.f, 1, 0, 0);
- break;
- case 3:
- glRotatef(90, 1, 0, 0);
- break;
- case 5:
- glRotatef(180, 0, 0, 1);
- break;
- }
-}
-
-void validate_framebuffer_object()
-{
- GLenum status;
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
- switch(status)
- {
- case GL_FRAMEBUFFER_COMPLETE:
- //framebuffer OK, no error.
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Missing Attachment." << llendl;
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Attachment." << llendl;
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED:
- /* choose different formats */
- llerrs << "Framebuffer unsupported." << llendl;
- break;
- default:
- llerrs << "Unknown framebuffer status." << llendl;
- break;
- }
-}
-
-void LLPipeline::bindScreenToTexture()
-{
-
-}
-
-static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
-
-void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
-{
- LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
- if (!(gPipeline.canUseVertexShaders() &&
- sRenderGlow))
- {
- return;
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- assertInitialized();
-
- if (gUseWireframe)
- {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
-
- U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-
- LLVector2 tc1(0,0);
- LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
- (F32) gViewerWindow->getWorldViewHeightRaw()*2);
-
- if (res_mod > 1)
- {
- tc2 /= (F32) res_mod;
- }
-
- LLFastTimer ftm(FTM_RENDER_BLOOM);
- gGL.color4f(1,1,1,1);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable cull(GL_CULL_FACE);
-
- enableLightsFullbright(LLColor4(1,1,1,1));
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- LLGLDisable test(GL_ALPHA_TEST);
-
- gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
-
- /*if (for_snapshot)
- {
- gGL.getTexUnit(0)->bind(&mGlow[1]);
- {
- //LLGLEnable stencil(GL_STENCIL_TEST);
- //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
- //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- //LLGLDisable blend(GL_BLEND);
-
- // If the snapshot is constructed from tiles, calculate which
- // tile we're in.
-
- //from LLViewerCamera::setPerpsective
- if (zoom_factor > 1.f)
- {
- int pos_y = subfield / llceil(zoom_factor);
- int pos_x = subfield - (pos_y*llceil(zoom_factor));
- F32 size = 1.f/zoom_factor;
-
- tc1.set(pos_x*size, pos_y*size);
- tc2 = tc1 + LLVector2(size,size);
- }
- else
- {
- tc2.set(1,1);
- }
-
- LLGLEnable blend(GL_BLEND);
- gGL.setSceneBlendType(LLRender::BT_ADD);
-
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.color4f(1,1,1,1);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,1);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(1,-1);
-
- gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
- gGL.vertex2f(1,1);
-
- gGL.end();
-
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- gGL.flush();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- return;
- }*/
-
- {
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[2].bindTarget();
- mGlow[2].clear();
- }
-
- gGlowExtractProgram.bind();
- F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f);
- F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
- F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
- LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
- LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
- gGlowExtractProgram.uniform1f("minLuminance", minLum);
- gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha);
- gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
- gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
- gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount);
- LLGLEnable blend_on(GL_BLEND);
- LLGLEnable test(GL_ALPHA_TEST);
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->disable();
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
- gGL.getTexUnit(0)->bind(&mScreen);
-
- gGL.color4f(1,1,1,1);
- gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
- mGlow[2].flush();
- }
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- // power of two between 1 and 1024
- U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
- const U32 glow_res = llmax(1,
- llmin(1024, 1 << glowResPow));
-
- S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2;
- F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res;
- // Use half the glow width if we have the res set to less than 9 so that it looks
- // almost the same in either case.
- if (glowResPow < 9)
- {
- delta *= 0.5f;
- }
- F32 strength = gSavedSettings.getF32("RenderGlowStrength");
-
- gGlowProgram.bind();
- gGlowProgram.uniform1f("glowStrength", strength);
-
- for (S32 i = 0; i < kernel; i++)
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[i%2].bindTarget();
- mGlow[i%2].clear();
- }
-
- if (i == 0)
- {
- gGL.getTexUnit(0)->bind(&mGlow[2]);
- }
- else
- {
- gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
- }
-
- if (i%2 == 0)
- {
- gGlowProgram.uniform2f("glowDelta", delta, 0);
- }
- else
- {
- gGlowProgram.uniform2f("glowDelta", 0, delta);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- mGlow[i%2].flush();
- }
-
- gGlowProgram.unbind();
-
- if (LLRenderTarget::sUseFBO)
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
-
- gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
- gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
- gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
- gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-
- tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(),
- (F32) gViewerWindow->getWorldViewHeightRaw());
-
- gGL.flush();
-
- LLVertexBuffer::unbind();
-
- if (LLPipeline::sRenderDeferred && !LLViewerCamera::getInstance()->cameraUnderWater())
- {
- LLGLSLShader* shader = &gDeferredPostProgram;
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- shader = &gDeferredGIFinalProgram;
- }
-
- LLGLDisable blend(GL_BLEND);
- bindDeferredShader(*shader);
-
- //depth of field focal plane calculations
-
- static F32 current_distance = 16.f;
- static F32 start_distance = 16.f;
- static F32 transition_time = 1.f;
-
- LLVector3 focus_point;
-
- LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
- if (obj && obj->mDrawable && obj->isSelected())
- {
- S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
- if (obj && obj->mDrawable)
- {
- LLFace* face = obj->mDrawable->getFace(face_idx);
- if (face)
- {
- focus_point = face->getPositionAgent();
- }
- }
- }
-
- if (focus_point.isExactlyZero())
- {
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- focus_point = gDebugRaycastIntersection;
- }
- else if (gAgentCamera.cameraMouselook())
- {
- gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
- NULL,
- &focus_point);
- }
- else
- {
- LLViewerObject* obj = gAgentCamera.getFocusObject();
- if (obj)
- {
- focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal());
- }
- else
- {
- focus_point = gDebugRaycastIntersection;
- }
- }
- }
-
- LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
- F32 target_distance = 16.f;
- if (!focus_point.isExactlyZero())
- {
- target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye);
- }
-
- if (transition_time >= 1.f &&
- fabsf(current_distance-target_distance)/current_distance > 0.01f)
- { //large shift happened, interpolate smoothly to new target distance
- transition_time = 0.f;
- start_distance = current_distance;
- }
- else if (transition_time < 1.f)
- { //currently in a transition, continue interpolating
- transition_time += 1.f/gSavedSettings.getF32("CameraFocusTransitionTime")*gFrameIntervalSeconds;
- transition_time = llmin(transition_time, 1.f);
-
- F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f;
- current_distance = start_distance + (target_distance-start_distance)*t;
- }
- else
- { //small or no change, just snap to target distance
- current_distance = target_distance;
- }
-
- //convert to mm
- F32 subject_distance = current_distance*1000.f;
- F32 fnumber = gSavedSettings.getF32("CameraFNumber");
- F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength");
-
- if (LLToolMgr::getInstance()->inBuildMode() || !gSavedSettings.getBOOL("RenderDepthOfField"))
- { //squish focal length when in build mode (or if DoF is disabled) so DoF doesn't make editing objects difficult
- default_focal_length = 5.f;
- }
-
- F32 fov = LLViewerCamera::getInstance()->getView();
-
- const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f;
- //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio");
-
- //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
-
- F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f);
- //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f);
-
- F32 focal_length = dv/(2*tanf(fov/2.f));
-
- //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
-
- // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
- // where N = fnumber
- // s2 = dot distance
- // s1 = subject distance
- // f = focal length
- //
-
- F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length));
- blur_constant /= 1000.f; //convert to meters for shader
- F32 magnification = focal_length/(subject_distance-focal_length);
-
- shader->uniform1f("focal_distance", -subject_distance/1000.f);
- shader->uniform1f("blur_constant", blur_constant);
- shader->uniform1f("tan_pixel_angle", tanf(1.f/LLDrawable::sCurPixelAngle));
- shader->uniform1f("magnification", magnification);
-
- S32 channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mScreen.bindTexture(0, channel);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
- //channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
- //if (channel > -1)
- //{
- //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- //}
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(*shader);
- }
- else
- {
- if (res_mod > 1)
- {
- tc2 /= (F32) res_mod;
- }
-
- U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
- LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
- buff->allocateBuffer(3,0,TRUE);
-
- LLStrider<LLVector3> v;
- LLStrider<LLVector2> uv1;
- LLStrider<LLVector2> uv2;
-
- buff->getVertexStrider(v);
- buff->getTexCoord0Strider(uv1);
- buff->getTexCoord1Strider(uv2);
-
- uv1[0] = LLVector2(0, 0);
- uv1[1] = LLVector2(0, 2);
- uv1[2] = LLVector2(2, 0);
-
- uv2[0] = LLVector2(0, 0);
- uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
- uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
-
- v[0] = LLVector3(-1,-1,0);
- v[1] = LLVector3(-1,3,0);
- v[2] = LLVector3(3,-1,0);
-
- buff->setBuffer(0);
-
- LLGLDisable blend(GL_BLEND);
-
- //tex unit 0
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
- gGL.getTexUnit(0)->bind(&mGlow[1]);
- gGL.getTexUnit(1)->activate();
- gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
-
-
- //tex unit 1
- gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
-
- gGL.getTexUnit(1)->bind(&mScreen);
- gGL.getTexUnit(1)->activate();
-
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- buff->setBuffer(mask);
- buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
-
- gGL.getTexUnit(1)->disable();
- gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- gGL.getTexUnit(0)->activate();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
- }
-
- if (LLRenderTarget::sUseFBO)
- { //copy depth buffer from mScreen to framebuffer
- LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
- 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
- {
- LLVector2 tc1(0,0);
- LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
- (F32) gViewerWindow->getWorldViewHeightRaw()*2);
-
- LLGLEnable blend(GL_BLEND);
- gGL.color4f(1,1,1,0.75f);
-
- gGL.getTexUnit(0)->bind(&mPhysicsDisplay);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
- gGL.flush();
- }
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
-}
-
-static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
-
-void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
-{
- LLFastTimer t(FTM_BIND_DEFERRED);
-
- if (noise_map == 0xFFFFFFFF)
- {
- noise_map = mNoiseMap;
- }
-
- LLGLState::checkTextureChannels();
-
- shader.bind();
- S32 channel = 0;
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(0,channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (gi_source)
- {
- BOOL has_gi = FALSE;
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(3, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(3, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
- if (channel > -1)
- {
- has_gi = TRUE;
- gGL.getTexUnit(channel)->bind(gi_source, TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
-
- glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
-
- stop_glerror();
- }
-
- if (has_gi)
- {
- F32 range_x = llmin(mGIRange.mV[0], 1.f);
- F32 range_y = llmin(mGIRange.mV[1], 1.f);
-
- LLVector2 scale(range_x,range_y);
-
- LLVector2 kern[25];
-
- for (S32 i = 0; i < 5; ++i)
- {
- for (S32 j = 0; j < 5; ++j)
- {
- S32 idx = i*5+j;
- kern[idx].mV[0] = (i-2)*0.5f;
- kern[idx].mV[1] = (j-2)*0.5f;
- kern[idx].scaleVec(scale);
- }
- }
-
- shader.uniform2fv("gi_kern", 25, (F32*) kern);
- shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m);
- shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m);
- shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m);
- shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m);
- }
- }
-
- /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(3, channel);
- }*/
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
-
- glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
-
- stop_glerror();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f inv_proj = projection.inverse();
-
- shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m);
- shader.uniform4f("viewport", (F32) gGLViewport[0],
- (F32) gGLViewport[1],
- (F32) gGLViewport[2],
- (F32) gGLViewport[3]);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- }
-
- stop_glerror();
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[light_index].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
- if (channel > -1)
- {
- mGlow[1].bindTexture(0, channel);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- gi_source->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mEdgeMap.bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[1].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[2].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
-
- stop_glerror();
-
- for (U32 i = 0; i < 4; i++)
- {
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- stop_glerror();
-
- F32 mat[16*6];
- for (U32 i = 0; i < 16; i++)
- {
- mat[i] = mSunShadowMatrix[0].m[i];
- mat[i+16] = mSunShadowMatrix[1].m[i];
- mat[i+32] = mSunShadowMatrix[2].m[i];
- mat[i+48] = mSunShadowMatrix[3].m[i];
- mat[i+64] = mSunShadowMatrix[4].m[i];
- mat[i+80] = mSunShadowMatrix[5].m[i];
- }
-
- shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat);
- shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat);
-
- stop_glerror();
-
- channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->enable(channel);
- cube_map->bind();
- F64* m = gGLModelView;
-
-
- F32 mat[] = { m[0], m[1], m[2],
- m[4], m[5], m[6],
- m[8], m[9], m[10] };
-
- shader.uniform3fv("env_mat[0]", 3, mat);
- shader.uniform3fv("env_mat", 3, mat);
- }
- }
-
- shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV);
- shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
- shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise"));
- shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize"));
-
- shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale"));
- shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale"));
-
- F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor");
- shader.uniform1f("ssao_factor", ssao_factor);
- shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor);
-
- LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect");
- F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
- F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
- // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
- // value factor, and scales remainder by saturation factor
- F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
- matrix_nondiag, matrix_diag, matrix_nondiag,
- matrix_nondiag, matrix_nondiag, matrix_diag};
- shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
-
- F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
- F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
-
- shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
- shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
- shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error);
- shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error);
- shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset"));
- shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias"));
-
- shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
- shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
- shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
- shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail"));
- shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange"));
- shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness"));
- shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance"));
- shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight"));
- shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
- shader.uniform1f("gi_sample_width", mGILightRadius);
- shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise"));
- shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation"));
- shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance"));
- shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight());
- shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight());
- shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff"));
- shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff"));
-
-
- if (shader.getUniformLocation("norm_mat") >= 0)
- {
- glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
- shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
-static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
-static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
-static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
-static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
-static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
-static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
-static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
-static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
-static LLFastTimer::DeclareTimer FTM_POST("Post");
-
-
-void LLPipeline::renderDeferredLighting()
-{
- if (!sCull)
- {
- return;
- }
-
- {
- LLFastTimer ftm(FTM_RENDER_DEFERRED);
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- {
- LLGLDepthTest depth(GL_TRUE);
- mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
-
- LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
-
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
-
- //ati doesn't seem to love actually using the stencil buffer on FBO's
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
- gGL.setColorMask(true, true);
-
- //draw a cube around every light
- LLVertexBuffer::unbind();
-
- LLGLEnable cull(GL_CULL_FACE);
- LLGLEnable blend(GL_BLEND);
-
- glh::matrix4f mat = glh_copy_matrix(gGLModelView);
-
- F32 vert[] =
- {
- -1,1,
- -1,-3,
- 3,1,
- };
- glVertexPointer(2, GL_FLOAT, 0, vert);
- glColor3f(1,1,1);
-
- {
- setupHWLights(NULL); //to set mSunDir;
- LLVector4 dir(mSunDir, 0.f);
- glh::vec4f tc(dir.mV);
- mat.mult_matrix_vec(tc);
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
- }
-
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0)
- {
- mDeferredLight[0].bindTarget();
- { //paint shadow/SSAO light map (direct lighting lightmap)
- LLFastTimer ftm(FTM_SUN_SHADOW);
- bindDeferredShader(gDeferredSunProgram, 0);
-
- glClearColor(1,1,1,1);
- mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
-
- const U32 slice = 32;
- F32 offset[slice*3];
- for (U32 i = 0; i < 4; i++)
- {
- for (U32 j = 0; j < 8; j++)
- {
- glh::vec3f v;
- v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
- v.normalize();
- inv_trans.mult_matrix_vec(v);
- v.normalize();
- offset[(i*8+j)*3+0] = v.v[0];
- offset[(i*8+j)*3+1] = v.v[2];
- offset[(i*8+j)*3+2] = v.v[1];
- }
- }
-
- gDeferredSunProgram.uniform3fv("offset", slice, offset);
- gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- unbindDeferredShader(gDeferredSunProgram);
- }
- mDeferredLight[0].flush();
- }
-
- { //global illumination specific block (still experimental)
- if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
- gSavedSettings.getBOOL("RenderDeferredGI"))
- {
- LLFastTimer ftm(FTM_EDGE_DETECTION);
- //generate edge map
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- {
- gDeferredEdgeProgram.bind();
- mEdgeMap.bindTarget();
- bindDeferredShader(gDeferredEdgeProgram);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gDeferredEdgeProgram);
- mEdgeMap.flush();
- }
- }
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- { //get luminance map from previous frame's light map
- LLGLEnable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- //static F32 fade = 1.f;
-
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- gLuminanceGatherProgram.bind();
- gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
- mLuminanceMap.bindTarget();
- bindDeferredShader(gLuminanceGatherProgram);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gLuminanceGatherProgram);
- mLuminanceMap.flush();
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- }
-
- { //paint noisy GI map (bounce lighting lightmap)
- LLFastTimer ftm(FTM_GI_TRACE);
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable test(GL_ALPHA_TEST);
-
- mGIMapPost[0].bindTarget();
-
- bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gDeferredGIProgram);
- mGIMapPost[0].flush();
- }
-
- U32 pass_count = 0;
- if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
- {
- pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128);
- }
-
- for (U32 i = 0; i < pass_count; ++i)
- { //gather/soften indirect lighting map
- LLFastTimer ftm(FTM_GI_GATHER);
- bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap);
- F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f);
- gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f);
- gDeferredPostGIProgram.uniform1f("kern_scale", blur_size);
- gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
-
- mGIMapPost[1].bindTarget();
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- mGIMapPost[1].flush();
- unbindDeferredShader(gDeferredPostGIProgram);
- bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap);
- mGIMapPost[0].bindTarget();
-
- gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f);
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- stop_glerror();
- }
- mGIMapPost[0].flush();
- unbindDeferredShader(gDeferredPostGIProgram);
- }
- }
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
- { //soften direct lighting lightmap
- LLFastTimer ftm(FTM_SOFTEN_SHADOW);
- //blur lightmap
- mDeferredLight[1].bindTarget();
-
- glClearColor(1,1,1,1);
- mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- bindDeferredShader(gDeferredBlurLightProgram);
-
- LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
- const U32 kern_length = 4;
- F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
- F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
-
- // sample symmetrically with the middle sample falling exactly on 0.0
- F32 x = 0.f;
-
- LLVector3 gauss[32]; // xweight, yweight, offset
-
- for (U32 i = 0; i < kern_length; i++)
- {
- gauss[i].mV[0] = llgaussian(x, go.mV[0]);
- gauss[i].mV[1] = llgaussian(x, go.mV[1]);
- gauss[i].mV[2] = x;
- x += 1.f;
- }
-
- gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
- gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
- gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- mDeferredLight[1].flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
-
- bindDeferredShader(gDeferredBlurLightProgram, 1);
- mDeferredLight[0].bindTarget();
-
- gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
- mDeferredLight[0].flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
- }
-
- stop_glerror();
- glPopMatrix();
- stop_glerror();
- glMatrixMode(GL_MODELVIEW);
- stop_glerror();
- glPopMatrix();
- stop_glerror();
-
- //copy depth and stencil from deferred screen
- //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[1].bindTarget();
- // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky
- glClearColor(0,0,0,0);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
- }
- else
- {
- mScreen.bindTarget();
- // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
- glClearColor(0,0,0,0);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredAtmospheric"))
- { //apply sunlight contribution
- LLFastTimer ftm(FTM_ATMOSPHERICS);
- bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]);
- {
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
-
- //full screen blit
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
- unbindDeferredShader(gDeferredSoftenProgram);
- }
-
- { //render sky
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- gPipeline.pushRenderTypeMask();
-
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
-
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- gPipeline.popRenderTypeMask();
- }
-
- BOOL render_local = gSavedSettings.getBOOL("RenderLocalLights");
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[1].flush();
- mDeferredLight[2].bindTarget();
- mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
- }
-
- if (render_local)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD);
- std::list<LLVector4> fullscreen_lights;
- LLDrawable::drawable_list_t spot_lights;
- LLDrawable::drawable_list_t fullscreen_spot_lights;
-
- for (U32 i = 0; i < 2; i++)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
-
- std::list<LLVector4> light_colors;
-
- LLVertexBuffer::unbind();
-
- F32 v[24];
- glVertexPointer(3, GL_FLOAT, 0, v);
-
- {
- bindDeferredShader(gDeferredLightProgram);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
- if (!volume)
- {
- continue;
- }
-
- if (volume->isAttachment())
- {
- if (!sRenderAttachedLights)
- {
- continue;
- }
- }
-
-
- LLVector4a center;
- center.load3(drawablep->getPositionAgent().mV);
- const F32* c = center.getF32ptr();
- F32 s = volume->getLightRadius()*1.5f;
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- if (col.magVecSquared() < 0.001f)
- {
- continue;
- }
-
- if (s <= 0.001f)
- {
- continue;
- }
-
- LLVector4a sa;
- sa.splat(s);
- if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
- {
- continue;
- }
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
- v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
- v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
- v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
-
- v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
- v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
- v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
- v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
-
- if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
- camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
- camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
- camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
- camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
- camera->getOrigin().mV[2] < c[2] - s - 0.2f)
- { //draw box if camera is outside box
- if (render_local)
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- spot_lights.push_back(drawablep);
- continue;
- }
-
- LLFastTimer ftm(FTM_LOCAL_LIGHTS);
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
- stop_glerror();
- }
- }
- else
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- fullscreen_spot_lights.push_back(drawablep);
- continue;
- }
-
- fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
- light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
- }
- }
- unbindDeferredShader(gDeferredLightProgram);
- }
-
- if (!spot_lights.empty())
- {
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- bindDeferredShader(gDeferredSpotLightProgram);
-
- gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector4a center;
- center.load3(drawablep->getPositionAgent().mV);
- const F32* c = center.getF32ptr();
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
- v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
- v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
- v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
-
- v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
- v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
- v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
- v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
-
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
- }
- gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredSpotLightProgram);
- }
-
- {
- bindDeferredShader(gDeferredMultiLightProgram);
-
- LLGLDepthTest depth(GL_FALSE);
-
- //full screen blit
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- U32 count = 0;
-
- const U32 max_count = 8;
- LLVector4 light[max_count];
- LLVector4 col[max_count];
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
-
- F32 far_z = 0.f;
-
- while (!fullscreen_lights.empty())
- {
- LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
- light[count] = fullscreen_lights.front();
- fullscreen_lights.pop_front();
- col[count] = light_colors.front();
- light_colors.pop_front();
-
- far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
-
- count++;
- if (count == max_count || fullscreen_lights.empty())
- {
- gDeferredMultiLightProgram.uniform1i("light_count", count);
- gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
- gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
- gDeferredMultiLightProgram.uniform1f("far_z", far_z);
- far_z = 0.f;
- count = 0;
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- }
- }
-
- unbindDeferredShader(gDeferredMultiLightProgram);
-
- bindDeferredShader(gDeferredMultiSpotLightProgram);
-
- gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- }
-
- gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredMultiSpotLightProgram);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- }
-
- gGL.setColorMask(true, true);
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[2].flush();
-
- mScreen.bindTarget();
- mScreen.clear(GL_COLOR_BUFFER_BIT);
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- { //mix various light maps (local, sun, gi)
- LLFastTimer ftm(FTM_POST);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]);
-
- gDeferredPostProgram.bind();
-
- LLVertexBuffer::unbind();
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
- glColor3f(1,1,1);
-
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- glDrawArrays(GL_TRIANGLES, 0, 3);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- unbindDeferredShader(gDeferredPostProgram);
- }
- }
- }
-
- { //render non-deferred geometry (alpha, fullbright, glow)
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_GLOW,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_GLOW,
- LLPipeline::RENDER_TYPE_PASS_GRASS,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- LLPipeline::RENDER_TYPE_AVATAR,
- END_RENDER_TYPES);
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- popRenderTypeMask();
- }
-
- {
- //render highlights, etc.
- renderHighlights();
- mHighlightFaces.clear();
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
- }
- }
-
- mScreen.flush();
-
-}
-
-void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
-{
- //construct frustum
- LLVOVolume* volume = drawablep->getVOVolume();
- LLVector3 params = volume->getSpotLightParams();
-
- F32 fov = params.mV[0];
- F32 focus = params.mV[1];
-
- LLVector3 pos = drawablep->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
- LLVector3 scale = volume->getScale();
-
- //get near clip plane
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = pos+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- //matrix from volume space to agent space
- LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
-
- glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
- glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
-
- glh::matrix4f screen_to_light = light_to_screen.inverse();
-
- F32 s = volume->getLightRadius()*1.5f;
- F32 near_clip = dist;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = s+dist-scale.mV[VZ];
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh::vec3f p1(0, 0, -(near_clip+0.01f));
- glh::vec3f p2(0, 0, -(near_clip+1.f));
-
- glh::vec3f screen_origin(0, 0, 0);
-
- light_to_screen.mult_matrix_vec(p1);
- light_to_screen.mult_matrix_vec(p2);
- light_to_screen.mult_matrix_vec(screen_origin);
-
- glh::vec3f n = p2-p1;
- n.normalize();
-
- F32 proj_range = far_clip - near_clip;
- glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
- screen_to_light = trans * light_proj * screen_to_light;
- shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m);
- shader.uniform1f("proj_near", near_clip);
- shader.uniform3fv("proj_p", 1, p1.v);
- shader.uniform3fv("proj_n", 1, n.v);
- shader.uniform3fv("proj_origin", 1, screen_origin.v);
- shader.uniform1f("proj_range", proj_range);
- shader.uniform1f("proj_ambiance", params.mV[2]);
- S32 s_idx = -1;
-
- for (U32 i = 0; i < 2; i++)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- s_idx = i;
- }
- }
-
- shader.uniform1i("proj_shadow_idx", s_idx);
-
- if (s_idx >= 0)
- {
- shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]);
- }
- else
- {
- shader.uniform1f("shadow_fade", 1.f);
- }
-
- {
- LLDrawable* potential = drawablep;
- //determine if this is a good light for casting shadows
- F32 m_pri = volume->getSpotLightPriority();
-
- for (U32 i = 0; i < 2; i++)
- {
- F32 pri = 0.f;
-
- if (mTargetShadowSpotLight[i].notNull())
- {
- pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
- }
-
- if (m_pri > pri)
- {
- LLDrawable* temp = mTargetShadowSpotLight[i];
- mTargetShadowSpotLight[i] = potential;
- potential = temp;
- m_pri = pri;
- }
- }
- }
-
- LLViewerTexture* img = volume->getLightTexture();
-
- S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- if (channel > -1 && img)
- {
- gGL.getTexUnit(channel)->bind(img);
-
- F32 lod_range = logf(img->getWidth())/logf(2.f);
-
- shader.uniform1f("proj_focus", focus);
- shader.uniform1f("proj_lod", lod_range);
- shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
- }
-}
-
-void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
-{
- stop_glerror();
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
- shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
-
- for (U32 i = 0; i < 4; i++)
- {
- if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
- {
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
- {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
-
- S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->disable();
- }
- }
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->activate();
- shader.unbind();
-
- LLGLState::checkTextureChannels();
-}
-
-inline float sgn(float a)
-{
- if (a > 0.0F) return (1.0F);
- if (a < 0.0F) return (-1.0F);
- return (0.0F);
-}
-
-void LLPipeline::generateWaterReflection(LLCamera& camera_in)
-{
- if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- BOOL skip_avatar_update = FALSE;
- if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
- {
- skip_avatar_update = TRUE;
- }
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
- }
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- LLCamera camera = camera_in;
- camera.setFar(camera.getFar()*0.87654321f);
- LLPipeline::sReflectionRender = TRUE;
-
- gPipeline.pushRenderTypeMask();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f mat;
-
- stop_glerror();
- LLPlane plane;
-
- F32 height = gAgent.getRegion()->getWaterHeight();
- F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
- F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
-
- //plane params
- LLVector3 pnorm;
- F32 pd;
-
- S32 water_clip = 0;
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //camera is above water, clip plane points up
- pnorm.setVec(0,0,1);
- pd = -height;
- plane.setVec(pnorm, pd);
- water_clip = -1;
- }
- else
- { //camera is below water, clip plane points down
- pnorm = LLVector3(0,0,-1);
- pd = height;
- plane.setVec(pnorm, pd);
- water_clip = 1;
- }
-
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //generate planar reflection map
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- glClearColor(0,0,0,0);
- mWaterRef.bindTarget();
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
- gGL.setColorMask(true, true);
- mWaterRef.clear();
- gGL.setColorMask(true, false);
-
- mWaterRef.getViewport(gGLViewport);
-
- stop_glerror();
-
- glPushMatrix();
-
- mat.set_scale(glh::vec3f(1,1,-1));
- mat.set_translate(glh::vec3f(0,0,height*2.f));
-
- glh::matrix4f current = glh_get_current_modelview();
-
- mat = current * mat;
-
- glh_set_current_modelview(mat);
- glLoadMatrixf(mat.m);
-
- LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
-
- glh::matrix4f inv_mat = mat.inverse();
-
- glh::vec3f origin(0,0,0);
- inv_mat.mult_matrix_vec(origin);
-
- camera.setOrigin(origin.v);
-
- glCullFace(GL_FRONT);
-
- static LLCullResult ref_result;
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- //initial sky pass (no user clip plane)
- { //mask out everything but the sky
- gPipeline.pushRenderTypeMask();
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
-
- static LLCullResult result;
- updateCull(camera, result);
- stateSort(camera, result);
-
- renderGeom(camera, TRUE);
-
- gPipeline.popRenderTypeMask();
- }
-
- gPipeline.pushRenderTypeMask();
-
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
-
- S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
- if (detail > 0)
- { //mask out selected geometry based on reflection detail
- if (detail < 4)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
- if (detail < 3)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- if (detail < 2)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
- }
- }
- }
-
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- LLGLDisable cull(GL_CULL_FACE);
- updateCull(camera, ref_result, -water_clip, &plane);
- stateSort(camera, ref_result);
- }
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
- {
- gPipeline.grabReferences(ref_result);
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- renderGeom(camera);
- }
- }
-
- gPipeline.popRenderTypeMask();
- }
- glCullFace(GL_BACK);
- glPopMatrix();
- mWaterRef.flush();
- glh_set_current_modelview(current);
- }
-
- camera.setOrigin(camera_in.getOrigin());
- //render distortion map
- static BOOL last_update = TRUE;
- if (last_update)
- {
- camera.setFar(camera_in.getFar());
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- END_RENDER_TYPES);
- stop_glerror();
-
- LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
-
- if (LLPipeline::sUnderWaterRender)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- END_RENDER_TYPES);
- }
- LLViewerCamera::updateFrustumPlanes(camera);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLColor4& col = LLDrawPoolWater::sWaterFogColor;
- glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- mWaterDis.bindTarget();
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
- mWaterDis.getViewport(gGLViewport);
-
- if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- //clip out geometry on the same side of water as the camera
- mat = glh_get_current_modelview();
- LLPlane plane(-pnorm, -(pd+pad));
-
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- static LLCullResult result;
- updateCull(camera, result, water_clip, &plane);
- stateSort(camera, result);
-
- gGL.setColorMask(true, true);
- mWaterDis.clear();
- gGL.setColorMask(true, false);
-
- renderGeom(camera);
- }
-
- LLPipeline::sUnderWaterRender = FALSE;
- mWaterDis.flush();
- }
- last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
-
- LLRenderTarget::unbindTarget();
-
- LLPipeline::sReflectionRender = FALSE;
-
- if (!LLRenderTarget::sUseFBO)
- {
- glClear(GL_DEPTH_BUFFER_BIT);
- }
- glClearColor(0.f, 0.f, 0.f, 0.f);
- gViewerWindow->setup3DViewport();
- gPipeline.popRenderTypeMask();
- LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
- LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
- LLPlane npnorm(-pnorm, -pd);
- LLViewerCamera::getInstance()->setUserClipPlane(npnorm);
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
- }
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- }
-}
-
-glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
-{
- glh::matrix4f ret;
-
- LLVector3 dirN;
- LLVector3 upN;
- LLVector3 lftN;
-
- lftN = dir % up;
- lftN.normVec();
-
- upN = lftN % dir;
- upN.normVec();
-
- dirN = dir;
- dirN.normVec();
-
- ret.m[ 0] = lftN[0];
- ret.m[ 1] = upN[0];
- ret.m[ 2] = -dirN[0];
- ret.m[ 3] = 0.f;
-
- ret.m[ 4] = lftN[1];
- ret.m[ 5] = upN[1];
- ret.m[ 6] = -dirN[1];
- ret.m[ 7] = 0.f;
-
- ret.m[ 8] = lftN[2];
- ret.m[ 9] = upN[2];
- ret.m[10] = -dirN[2];
- ret.m[11] = 0.f;
-
- ret.m[12] = -(lftN*pos);
- ret.m[13] = -(upN*pos);
- ret.m[14] = dirN*pos;
- ret.m[15] = 1.f;
-
- return ret;
-}
-
-glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
-{
- glh::matrix4f ret;
- ret.m[ 0] = 2/(max[0]-min[0]);
- ret.m[ 4] = 0;
- ret.m[ 8] = 0;
- ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
-
- ret.m[ 1] = 0;
- ret.m[ 5] = 2/(max[1]-min[1]);
- ret.m[ 9] = 0;
- ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
-
- ret.m[ 2] = 0;
- ret.m[ 6] = 0;
- ret.m[10] = 2/(max[2]-min[2]);
- ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
-
- ret.m[ 3] = 0;
- ret.m[ 7] = 0;
- ret.m[11] = 0;
- ret.m[15] = 1;
-
- return ret;
-}
-
-static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
-static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
-static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
-
-void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
-{
- LLFastTimer t(FTM_SHADOW_RENDER);
-
- //clip out geometry on the same side of water as the camera
- S32 occlude = LLPipeline::sUseOcclusion;
- if (!use_occlusion)
- {
- LLPipeline::sUseOcclusion = 0;
- }
- LLPipeline::sShadowRender = TRUE;
-
- U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY };
- LLGLEnable cull(GL_CULL_FACE);
-
- if (use_shader)
- {
- gDeferredShadowProgram.bind();
- }
-
- updateCull(shadow_cam, result);
- stateSort(shadow_cam, result);
-
- //generate shadow map
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(proj.m);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadMatrixd(gGLModelView);
-
- stop_glerror();
- gGLLastMatrix = NULL;
-
- {
- //LLGLDepthTest depth(GL_TRUE);
- //glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- glColor4f(1,1,1,1);
-
- stop_glerror();
-
- gGL.setColorMask(false, false);
-
- //glCullFace(GL_FRONT);
-
- LLVertexBuffer::unbind();
-
- {
- LLFastTimer ftm(FTM_SHADOW_SIMPLE);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->disable();
- for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
- {
- renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
- }
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- }
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- renderGeomShadow(shadow_cam);
- gDeferredShadowProgram.bind();
- }
- else
- {
- renderGeomShadow(shadow_cam);
- }
-
- {
- LLFastTimer ftm(FTM_SHADOW_ALPHA);
- LLGLEnable test(GL_ALPHA_TEST);
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
- renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
- glColor4f(1,1,1,1);
- renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- }
-
- //glCullFace(GL_BACK);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(shadow_cam);
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- }
-
- gGL.setColorMask(true, true);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- gGLLastMatrix = NULL;
-
- LLPipeline::sUseOcclusion = occlude;
- LLPipeline::sShadowRender = FALSE;
-}
-
-static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
-BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
-{
- LLFastTimer t(FTM_VISIBLE_CLOUD);
- //get point cloud of intersection of frust and min, max
-
- if (getVisibleExtents(camera, min, max))
- {
- return FALSE;
- }
-
- //get set of planes on bounding box
- LLPlane bp[] = {
- LLPlane(min, LLVector3(-1,0,0)),
- LLPlane(min, LLVector3(0,-1,0)),
- LLPlane(min, LLVector3(0,0,-1)),
- LLPlane(max, LLVector3(1,0,0)),
- LLPlane(max, LLVector3(0,1,0)),
- LLPlane(max, LLVector3(0,0,1))};
-
- //potential points
- std::vector<LLVector3> pp;
-
- //add corners of AABB
- pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
-
- //add corners of camera frustum
- for (U32 i = 0; i < 8; i++)
- {
- pp.push_back(camera.mAgentFrustum[i]);
- }
-
-
- //bounding box line segments
- U32 bs[] =
- {
- 0,1,
- 1,3,
- 3,2,
- 2,0,
-
- 4,5,
- 5,7,
- 7,6,
- 6,4,
-
- 0,4,
- 1,5,
- 3,7,
- 2,6
- };
-
- for (U32 i = 0; i < 12; i++)
- { //for each line segment in bounding box
- for (U32 j = 0; j < 6; j++)
- { //for each plane in camera frustum
- const LLPlane& cp = camera.getAgentPlane(j);
- const LLVector3& v1 = pp[bs[i*2+0]];
- const LLVector3& v2 = pp[bs[i*2+1]];
- LLVector3 n;
- cp.getVector3(n);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- //camera frustum line segments
- const U32 fs[] =
- {
- 0,1,
- 1,2,
- 2,3,
- 3,0,
-
- 4,5,
- 5,6,
- 6,7,
- 7,4,
-
- 0,4,
- 1,5,
- 2,6,
- 3,7
- };
-
- LLVector3 center = (max+min)*0.5f;
- LLVector3 size = (max-min)*0.5f;
-
- for (U32 i = 0; i < 12; i++)
- {
- for (U32 j = 0; j < 6; ++j)
- {
- const LLVector3& v1 = pp[fs[i*2+0]+8];
- const LLVector3& v2 = pp[fs[i*2+1]+8];
- const LLPlane& cp = bp[j];
- LLVector3 n;
- cp.getVector3(n);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
- max+LLVector3(0.05f,0.05f,0.05f) };
-
- for (U32 i = 0; i < pp.size(); ++i)
- {
- bool found = true;
-
- const F32* p = pp[i].mV;
-
- for (U32 j = 0; j < 3; ++j)
- {
- if (p[j] < ext[0].mV[j] ||
- p[j] > ext[1].mV[j])
- {
- found = false;
- break;
- }
- }
-
- for (U32 j = 0; j < 6; ++j)
- {
- const LLPlane& cp = camera.getAgentPlane(j);
- F32 dist = cp.dist(pp[i]);
- if (dist > 0.05f) //point is above some plane, not contained
- {
- found = false;
- break;
- }
- }
-
- if (found)
- {
- fp.push_back(pp[i]);
- }
- }
-
- if (fp.empty())
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc)
-{
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3)
- {
- return;
- }
-
- LLVector3 up;
-
- //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV);
-
- if (lightDir.mV[2] > 0.5f)
- {
- up = LLVector3(1,0,0);
- }
- else
- {
- up = LLVector3(0, 0, 1);
- }
-
-
- F32 gi_range = gSavedSettings.getF32("RenderGIRange");
-
- U32 res = mGIMap.getWidth();
-
- F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f);
-
- //set radius to range at which distance attenuation of incoming photons is near 0
-
- F32 lrad = sqrtf(1.f/(atten*0.01f));
-
- F32 lrange = lrad+gi_range*0.5f;
-
- LLVector3 pad(lrange,lrange,lrange);
-
- glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up);
-
- LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f);
-
- glh::vec3f scp(cp.mV);
- view.mult_matrix_vec(scp);
- cp.setVec(scp.v);
-
- F32 pix_width = lrange/(res*0.5f);
-
- //move cp to the nearest pix_width
- for (U32 i = 0; i < 3; i++)
- {
- cp.mV[i] = llround(cp.mV[i], pix_width);
- }
-
- LLVector3 min = cp-pad;
- LLVector3 max = cp+pad;
-
- //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point
- mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res;
- mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res;
- mGILightRadius = lrad/lrange*0.5f;
-
- glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
-
- LLCamera sun_cam = camera;
-
- glh::matrix4f eye_view = glh_get_current_modelview();
-
- //get eye space to camera space matrix
- mGIMatrix = view*eye_view.inverse();
- mGINormalMatrix = mGIMatrix.inverse().transpose();
- mGIInvProj = proj.inverse();
- mGIMatrixProj = proj*mGIMatrix;
-
- //translate and scale to [0,1]
- glh::matrix4f trans(.5f, 0.f, 0.f, .5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- mGIMatrixProj = trans*mGIMatrixProj;
-
- glh_set_current_modelview(view);
- glh_set_current_projection(proj);
-
- LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE);
-
- sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
- static LLCullResult result;
-
- pushRenderTypeMask();
-
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- END_RENDER_TYPES);
-
-
-
- S32 occlude = LLPipeline::sUseOcclusion;
- //LLPipeline::sUseOcclusion = 0;
- LLPipeline::sShadowRender = TRUE;
-
- //only render large objects into GI map
- sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize");
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE;
- mGIMap.bindTarget();
-
- F64 last_modelview[16];
- F64 last_projection[16];
- for (U32 i = 0; i < 16; i++)
- {
- last_modelview[i] = gGLLastModelView[i];
- last_projection[i] = gGLLastProjection[i];
- gGLLastModelView[i] = mGIModelview.m[i];
- gGLLastProjection[i] = mGIProjection.m[i];
- }
-
- sun_cam.setOrigin(0.f, 0.f, 0.f);
- updateCull(sun_cam, result);
- stateSort(sun_cam, result);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = last_modelview[i];
- gGLLastProjection[i] = last_projection[i];
- }
-
- mGIProjection = proj;
- mGIModelview = view;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- //generate GI map
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(proj.m);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadMatrixf(view.m);
-
- stop_glerror();
- gGLLastMatrix = NULL;
-
- mGIMap.clear();
-
- {
- //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
- renderGeomDeferred(camera);
- }
-
- mGIMap.flush();
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- gGLLastMatrix = NULL;
-
- LLPipeline::sUseOcclusion = occlude;
- LLPipeline::sShadowRender = FALSE;
- sMinRenderSize = 0.f;
-
- popRenderTypeMask();
-
-}
-
-void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
-{
- if (obj && obj->getVolume())
- {
- for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
- {
- renderHighlight(*iter, fade);
- }
-
- LLDrawable* drawable = obj->mDrawable;
- if (drawable)
- {
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- if (face)
- {
- face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
- }
- }
- }
- }
-}
-
-void LLPipeline::generateHighlight(LLCamera& camera)
-{
- //render highlighted object as white into offscreen render target
- if (mHighlightObject.notNull())
- {
- mHighlightSet.insert(HighlightItem(mHighlightObject));
- }
-
- if (!mHighlightSet.empty())
- {
- F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime");
-
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- mHighlight.bindTarget();
- disableLights();
- gGL.setColorMask(true, true);
- mHighlight.clear();
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
- {
- std::set<HighlightItem>::iterator cur_iter = iter++;
-
- if (cur_iter->mItem.isNull())
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
-
- if (cur_iter->mItem == mHighlightObject)
- {
- cur_iter->incrFade(transition);
- }
- else
- {
- cur_iter->incrFade(-transition);
- if (cur_iter->mFade <= 0.f)
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
- }
-
- renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
- }
-
- mHighlight.flush();
- gGL.setColorMask(true, false);
- gViewerWindow->setup3DViewport();
- }
-}
-
-
-void LLPipeline::generateSunShadow(LLCamera& camera)
-{
- if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0)
- {
- return;
- }
-
- F64 last_modelview[16];
- F64 last_projection[16];
- for (U32 i = 0; i < 16; i++)
- { //store last_modelview of world camera
- last_modelview[i] = gGLLastModelView[i];
- last_projection[i] = gGLLastProjection[i];
- }
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- END_RENDER_TYPES);
-
- gGL.setColorMask(false, false);
-
- //get sun view matrix
-
- //store current projection/modelview matrix
- glh::matrix4f saved_proj = glh_get_current_projection();
- glh::matrix4f saved_view = glh_get_current_modelview();
- glh::matrix4f inv_view = saved_view.inverse();
-
- glh::matrix4f view[6];
- glh::matrix4f proj[6];
-
- //clip contains parallel split distances for 3 splits
- LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
-
- //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
-
- //far clip on last split is minimum of camera view distance and 128
- mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
-
- clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
- mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
-
- //currently used for amount to extrude frusta corners for constructing shadow frusta
- LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
- //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
-
- //put together a universal "near clip" plane for shadow frusta
- LLPlane shadow_near_clip;
- {
- LLVector3 p = gAgent.getPositionAgent();
- p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f;
- shadow_near_clip.setVec(p, mSunDir);
- }
-
- LLVector3 lightDir = -mSunDir;
- lightDir.normVec();
-
- glh::vec3f light_dir(lightDir.mV);
-
- //create light space camera matrix
-
- LLVector3 at = lightDir;
-
- LLVector3 up = camera.getAtAxis();
-
- if (fabsf(up*lightDir) > 0.75f)
- {
- up = camera.getUpAxis();
- }
-
- /*LLVector3 left = up%at;
- up = at%left;*/
-
- up.normVec();
- at.normVec();
-
-
- LLCamera main_camera = camera;
-
- F32 near_clip = 0.f;
- {
- //get visible point cloud
- std::vector<LLVector3> fp;
-
- main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
-
- LLVector3 min,max;
- getVisiblePointCloud(main_camera,min,max,fp);
-
- if (fp.empty())
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[0] = main_camera;
- mShadowExtents[0][0] = min;
- mShadowExtents[0][1] = max;
-
- mShadowFrustPoints[0].clear();
- mShadowFrustPoints[1].clear();
- mShadowFrustPoints[2].clear();
- mShadowFrustPoints[3].clear();
- }
- popRenderTypeMask();
- return;
- }
-
- generateGI(camera, lightDir, fp);
-
- //get good split distances for frustum
- for (U32 i = 0; i < fp.size(); ++i)
- {
- glh::vec3f v(fp[i].mV);
- saved_view.mult_matrix_vec(v);
- fp[i].setVec(v.v);
- }
-
- min = fp[0];
- max = fp[0];
-
- //get camera space bounding box
- for (U32 i = 1; i < fp.size(); ++i)
- {
- update_min_max(min, max, fp[i]);
- }
-
- near_clip = -max.mV[2];
- F32 far_clip = -min.mV[2]*2.f;
-
- //far_clip = llmin(far_clip, 128.f);
- far_clip = llmin(far_clip, camera.getFar());
-
- F32 range = far_clip-near_clip;
-
- LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent");
-
- F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
-
- da = powf(da, split_exp.mV[2]);
-
-
- F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
-
-
- for (U32 i = 0; i < 4; ++i)
- {
- F32 x = (F32)(i+1)/4.f;
- x = powf(x, sxp);
- mSunClipPlanes.mV[i] = near_clip+range*x;
- }
- }
-
- // convenience array of 4 near clip plane distances
- F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
-
- for (S32 j = 0; j < 4; j++)
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustPoints[j].clear();
- }
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
-
- //restore render matrices
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- LLVector3 eye = camera.getOrigin();
-
- //camera used for shadow cull/render
- LLCamera shadow_cam;
-
- //create world space camera frustum for this split
- shadow_cam = camera;
- shadow_cam.setFar(16.f);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- LLVector3* frust = shadow_cam.mAgentFrustum;
-
- LLVector3 pn = shadow_cam.getAtAxis();
-
- LLVector3 min, max;
-
- //construct 8 corners of split frustum section
- for (U32 i = 0; i < 4; i++)
- {
- LLVector3 delta = frust[i+4]-eye;
- delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
- delta.normVec();
- F32 dp = delta*pn;
- frust[i] = eye + (delta*dist[j]*0.95f)/dp;
- frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
- }
-
- shadow_cam.calcAgentFrustumPlanes(frust);
- shadow_cam.mFrustumCornerDist = 0.f;
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[j] = shadow_cam;
- }
-
- std::vector<LLVector3> fp;
-
- if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
- {
- //no possible shadow receivers
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = LLVector3();
- mShadowExtents[j][1] = LLVector3();
- mShadowCamera[j+4] = shadow_cam;
- }
-
- mShadow[j].bindTarget();
- {
- LLGLDepthTest depth(GL_TRUE);
- mShadow[j].clear();
- }
- mShadow[j].flush();
-
- mShadowError.mV[j] = 0.f;
- mShadowFOV.mV[j] = 0.f;
-
- continue;
- }
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = min;
- mShadowExtents[j][1] = max;
- mShadowFrustPoints[j] = fp;
- }
-
-
- //find a good origin for shadow projection
- LLVector3 origin;
-
- //get a temporary view projection
- view[j] = look(camera.getOrigin(), lightDir, -up);
-
- std::vector<LLVector3> wpf;
-
- for (U32 i = 0; i < fp.size(); i++)
- {
- glh::vec3f p = glh::vec3f(fp[i].mV);
- view[j].mult_matrix_vec(p);
- wpf.push_back(LLVector3(p.v));
- }
-
- min = wpf[0];
- max = wpf[0];
-
- for (U32 i = 0; i < fp.size(); ++i)
- { //get AABB in camera space
- update_min_max(min, max, wpf[i]);
- }
-
- // Construct a perspective transform with perspective along y-axis that contains
- // points in wpf
- //Known:
- // - far clip plane
- // - near clip plane
- // - points in frustum
- //Find:
- // - origin
-
- //get some "interesting" points of reference
- LLVector3 center = (min+max)*0.5f;
- LLVector3 size = (max-min)*0.5f;
- LLVector3 near_center = center;
- near_center.mV[1] += size.mV[1]*2.f;
-
-
- //put all points in wpf in quadrant 0, reletive to center of min/max
- //get the best fit line using least squares
- F32 bfm = 0.f;
- F32 bfb = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- wpf[i] -= center;
- wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
- wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
- }
-
- if (!wpf.empty())
- {
- F32 sx = 0.f;
- F32 sx2 = 0.f;
- F32 sy = 0.f;
- F32 sxy = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- sx += wpf[i].mV[0];
- sx2 += wpf[i].mV[0]*wpf[i].mV[0];
- sy += wpf[i].mV[1];
- sxy += wpf[i].mV[0]*wpf[i].mV[1];
- }
-
- bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
- bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
- }
-
- {
- // best fit line is y=bfm*x+bfb
-
- //find point that is furthest to the right of line
- F32 off_x = -1.f;
- LLVector3 lp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- //y = bfm*x+bfb
- //x = (y-bfb)/bfm
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
-
- lx = wpf[i].mV[0]-lx;
-
- if (off_x < lx)
- {
- off_x = lx;
- lp = wpf[i];
- }
- }
-
- //get line with slope bfm through lp
- // bfb = y-bfm*x
- bfb = lp.mV[1]-bfm*lp.mV[0];
-
- //calculate error
- mShadowError.mV[j] = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
- mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
- }
-
- mShadowError.mV[j] /= wpf.size();
- mShadowError.mV[j] /= size.mV[0];
-
- if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff"))
- { //just use ortho projection
- mShadowFOV.mV[j] = -1.f;
- origin.clearVec();
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //origin is where line x = 0;
- origin.setVec(0,bfb,0);
-
- F32 fovz = 1.f;
- F32 fovx = 1.f;
-
- LLVector3 zp;
- LLVector3 xp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- if (fovz > -atz.mV[1])
- {
- zp = wpf[i];
- fovz = -atz.mV[1];
- }
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- if (fovx > -atx.mV[1])
- {
- fovx = -atx.mV[1];
- xp = wpf[i];
- }
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f);
-
- mShadowFOV.mV[j] = fovx;
-
- if (fovx < cutoff && fovz > cutoff)
- {
- //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
- F32 d = zp.mV[2]/tan(cutoff);
- F32 ny = zp.mV[1] + fabsf(d);
-
- origin.mV[1] = ny;
-
- fovz = 1.f;
- fovx = 1.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- fovz = llmin(fovz, -atz.mV[1]);
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- fovx = llmin(fovx, -atx.mV[1]);
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
- {
- // llerrs << "WTF?" << llendl;
- }
-
- mShadowFOV.mV[j] = cutoff;
- }
-
-
- origin += center;
-
- F32 ynear = -(max.mV[1]-origin.mV[1]);
- F32 yfar = -(min.mV[1]-origin.mV[1]);
-
- if (ynear < 0.1f) //keep a sensible near clip plane
- {
- F32 diff = 0.1f-ynear;
- origin.mV[1] += diff;
- ynear += diff;
- yfar += diff;
- }
-
- if (fovx > cutoff)
- { //just use ortho projection
- origin.clearVec();
- mShadowError.mV[j] = -1.f;
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //get perspective projection
- view[j] = view[j].inverse();
-
- glh::vec3f origin_agent(origin.mV);
-
- //translate view to origin
- view[j].mult_matrix_vec(origin_agent);
-
- eye = LLVector3(origin_agent.v);
-
- if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustOrigin[j] = eye;
- }
-
- view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
-
- F32 fx = 1.f/tanf(fovx);
- F32 fz = 1.f/tanf(fovz);
-
- proj[j] = glh::matrix4f(-fx, 0, 0, 0,
- 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
- 0, 0, -fz, 0,
- 0, -1.f, 0, 0);
- }
- }
- }
-
- //shadow_cam.setFar(128.f);
- shadow_cam.setOriginAndLookAt(eye, up, center);
-
- shadow_cam.setOrigin(0,0,0);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
- shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = mShadowModelview[j].m[i];
- gGLLastProjection[i] = mShadowProjection[j].m[i];
- }
-
- mShadowModelview[j] = view[j];
- mShadowProjection[j] = proj[j];
-
-
- mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
-
- stop_glerror();
-
- mShadow[j].bindTarget();
- mShadow[j].getViewport(gGLViewport);
- mShadow[j].clear();
-
- {
- static LLCullResult result[4];
-
- //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
- renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
- }
-
- mShadow[j].flush();
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- mShadowCamera[j+4] = shadow_cam;
- }
- }
-
-
- //hack to disable projector shadows
- bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
-
- if (gen_shadow)
- {
- F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
-
- //update shadow targets
- for (U32 i = 0; i < 2; i++)
- { //for each current shadow
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
-
- if (mShadowSpotLight[i].notNull() &&
- (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
- mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
- { //keep this spotlight
- mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
- }
- else
- { //fade out this light
- mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
-
- if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
- { //faded out, grab one of the pending spots (whichever one isn't already taken)
- if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[0];
- }
- else
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[1];
- }
- }
- }
- }
-
- for (S32 i = 0; i < 2; i++)
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- if (mShadowSpotLight[i].isNull())
- {
- continue;
- }
-
- LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
-
- if (!volume)
- {
- mShadowSpotLight[i] = NULL;
- continue;
- }
-
- LLDrawable* drawable = mShadowSpotLight[i];
-
- LLVector3 params = volume->getSpotLightParams();
- F32 fov = params.mV[0];
-
- //get agent->light space matrix (modelview)
- LLVector3 center = drawable->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
-
- //get near clip plane
- LLVector3 scale = volume->getScale();
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = center+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- LLMatrix4 mat(quat, LLVector4(origin, 1.f));
-
- view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
-
- view[i+4] = view[i+4].inverse();
-
- //get perspective matrix
- F32 near_clip = dist+0.01f;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = dist+volume->getLightRadius()*1.5f;
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[i+4]);
- glh_set_current_projection(proj[i+4]);
-
- mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
-
- for (U32 j = 0; j < 16; j++)
- {
- gGLLastModelView[j] = mShadowModelview[i+4].m[j];
- gGLLastProjection[j] = mShadowProjection[i+4].m[j];
- }
-
- mShadowModelview[i+4] = view[i+4];
- mShadowProjection[i+4] = proj[i+4];
-
- LLCamera shadow_cam = camera;
- shadow_cam.setFar(far_clip);
- shadow_cam.setOrigin(origin);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- stop_glerror();
-
- mShadow[i+4].bindTarget();
- mShadow[i+4].getViewport(gGLViewport);
- mShadow[i+4].clear();
-
- static LLCullResult result[2];
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
-
- renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
-
- mShadow[i+4].flush();
- }
- }
-
- if (!gSavedSettings.getBOOL("CameraOffset"))
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
- }
- else
- {
- glh_set_current_modelview(view[1]);
- glh_set_current_projection(proj[1]);
- glLoadMatrixf(view[1].m);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(proj[1].m);
- glMatrixMode(GL_MODELVIEW);
- }
- gGL.setColorMask(true, false);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = last_modelview[i];
- gGLLastProjection[i] = last_projection[i];
- }
-
- popRenderTypeMask();
-}
-
-void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
-{
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!group->isDead() &&
- (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
- gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
- group->mDrawMap.find(type) != group->mDrawMap.end())
- {
- pass->renderGroup(group,type,mask,texture);
- }
- }
-}
-
-void LLPipeline::generateImpostor(LLVOAvatar* avatar)
-{
- LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- static LLCullResult result;
- result.clear();
- grabReferences(result);
-
- if (!avatar || !avatar->mDrawable)
- {
- return;
- }
-
- assertInitialized();
-
- BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
-
- pushRenderTypeMask();
-
- if (muted)
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- }
- else
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- END_RENDER_TYPES);
- }
-
- S32 occlusion = sUseOcclusion;
- sUseOcclusion = 0;
- sReflectionRender = sRenderDeferred ? FALSE : TRUE;
- sShadowRender = TRUE;
- sImpostorRender = TRUE;
-
- LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
- markVisible(avatar->mDrawable, *viewer_camera);
- LLVOAvatar::sUseImpostors = FALSE;
-
- LLVOAvatar::attachment_map_t::iterator iter;
- for (iter = avatar->mAttachmentPoints.begin();
- iter != avatar->mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment *attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- if (LLViewerObject* attached_object = (*attachment_iter))
- {
- markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
- }
- }
- }
-
- stateSort(*LLViewerCamera::getInstance(), result);
-
- const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
- LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
-
- LLCamera camera = *viewer_camera;
-
- camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
-
- LLVector2 tdim;
-
-
- LLVector4a half_height;
- half_height.setSub(ext[1], ext[0]);
- half_height.mul(0.5f);
-
- LLVector4a left;
- left.load3(camera.getLeftAxis().mV);
- left.mul(left);
- left.normalize3fast();
-
- LLVector4a up;
- up.load3(camera.getUpAxis().mV);
- up.mul(up);
- up.normalize3fast();
-
- tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
- tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
-
- F32 distance = (pos-camera.getOrigin()).length();
- F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
- F32 aspect = tdim.mV[0]/tdim.mV[1];
- glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
- glh_set_current_projection(persp);
- glLoadMatrixf(persp.m);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glh::matrix4f mat;
- camera.getOpenGLTransform(mat.m);
-
- mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
-
- glLoadMatrixf(mat.m);
- glh_set_current_modelview(mat);
-
- glClearColor(0.0f,0.0f,0.0f,0.0f);
- gGL.setColorMask(true, true);
-
- // get the number of pixels per angle
- F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
-
- //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
- U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
- U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
-
- if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
- resY != avatar->mImpostor.getHeight())
- {
- avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
-
- if (LLPipeline::sRenderDeferred)
- {
- addDeferredAttachments(avatar->mImpostor);
- }
-
- gGL.getTexUnit(0)->bind(&avatar->mImpostor);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- avatar->mImpostor.bindTarget();
-
- if (LLPipeline::sRenderDeferred)
- {
- avatar->mImpostor.clear();
- renderGeomDeferred(camera);
- renderGeomPostDeferred(camera);
- }
- else
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, resX, resY);
- avatar->mImpostor.clear();
- renderGeom(camera);
- }
-
- { //create alpha mask based on depth buffer (grey out if muted)
- if (LLPipeline::sRenderDeferred)
- {
- GLuint buff = GL_COLOR_ATTACHMENT0;
- glDrawBuffersARB(1, &buff);
- }
-
- LLGLDisable blend(GL_BLEND);
-
- if (muted)
- {
- gGL.setColorMask(true, true);
- }
- else
- {
- gGL.setColorMask(false, true);
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
-
- gGL.flush();
-
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- static const F32 clip_plane = 0.99999f;
-
- gGL.color4ub(64,64,64,255);
- gGL.begin(LLRender::QUADS);
- gGL.vertex3f(-1, -1, clip_plane);
- gGL.vertex3f(1, -1, clip_plane);
- gGL.vertex3f(1, 1, clip_plane);
- gGL.vertex3f(-1, 1, clip_plane);
- gGL.end();
- gGL.flush();
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
- avatar->mImpostor.flush();
-
- avatar->setImpostorDim(tdim);
-
- LLVOAvatar::sUseImpostors = TRUE;
- sUseOcclusion = occlusion;
- sReflectionRender = FALSE;
- sImpostorRender = FALSE;
- sShadowRender = FALSE;
- popRenderTypeMask();
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- avatar->mNeedsImpostorUpdate = FALSE;
- avatar->cacheImpostorValues();
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-}
-
-BOOL LLPipeline::hasRenderBatches(const U32 type) const
-{
- return sCull->getRenderMapSize(type) > 0;
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
-{
- return sCull->beginRenderMap(type);
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
-{
- return sCull->endRenderMap(type);
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
-{
- return sCull->beginAlphaGroups();
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
-{
- return sCull->endAlphaGroups();
-}
-
-BOOL LLPipeline::hasRenderType(const U32 type) const
-{
- // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
- // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
- // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
- return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
-}
-
-void LLPipeline::setRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = TRUE;
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- return TRUE;
- }
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- return FALSE;
-}
-
-void LLPipeline::pushRenderTypeMask()
-{
- std::string cur_mask;
- cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.push(cur_mask);
-}
-
-void LLPipeline::popRenderTypeMask()
-{
- if (mRenderTypeEnableStack.empty())
- {
- llerrs << "Depleted render type stack." << llendl;
- }
-
- memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.pop();
-}
-
-void LLPipeline::andRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- BOOL tmp[NUM_RENDER_TYPES];
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- tmp[i] = FALSE;
- }
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- tmp[type] = TRUE;
- }
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = tmp[i];
- }
-
-}
-
-void LLPipeline::clearRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = FALSE;
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-
+/**
+ * @file pipeline.cpp
+ * @brief Rendering pipeline.
+ *
+ * $LicenseInfo:firstyear=2005&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+
+// library includes
+#include "llaudioengine.h" // For debugging.
+#include "imageids.h"
+#include "llerror.h"
+#include "llviewercontrol.h"
+#include "llfasttimer.h"
+#include "llfontgl.h"
+#include "llmemtype.h"
+#include "llnamevalue.h"
+#include "llpointer.h"
+#include "llprimitive.h"
+#include "llvolume.h"
+#include "material_codes.h"
+#include "timing.h"
+#include "v3color.h"
+#include "llui.h"
+#include "llglheaders.h"
+#include "llrender.h"
+#include "llwindow.h" // swapBuffers()
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolavatar.h"
+#include "lldrawpoolground.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpooltree.h"
+#include "lldrawpoolwater.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfloatertelehub.h"
+#include "llfloaterreg.h"
+#include "llgldbg.h"
+#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h"
+#include "lllightconstants.h"
+#include "llmeshrepository.h"
+#include "llresmgr.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "lltracker.h"
+#include "lltool.h"
+#include "lltoolmgr.h"
+#include "llviewercamera.h"
+#include "llviewermediafocus.h"
+#include "llviewertexturelist.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h" // for audio debugging.
+#include "llviewerwindow.h" // For getSpinAxis
+#include "llvoavatarself.h"
+#include "llvoground.h"
+#include "llvosky.h"
+#include "llvotree.h"
+#include "llvovolume.h"
+#include "llvosurfacepatch.h"
+#include "llvowater.h"
+#include "llvotree.h"
+#include "llvopartgroup.h"
+#include "llworld.h"
+#include "llcubemap.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llviewerjoystick.h"
+#include "llviewerdisplay.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llspatialpartition.h"
+#include "llmutelist.h"
+#include "lltoolpie.h"
+#include "llcurl.h"
+
+
+void check_stack_depth(S32 stack_depth)
+{
+ if (gDebugGL || gDebugSession)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth != stack_depth)
+ {
+ if (gDebugSession)
+ {
+ ll_fail("GL matrix stack corrupted.");
+ }
+ else
+ {
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ }
+ }
+}
+
+#ifdef _DEBUG
+// Debug indices is disabled for now for debug performance - djs 4/24/02
+//#define DEBUG_INDICES
+#else
+//#define DEBUG_INDICES
+#endif
+
+const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
+const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
+const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
+const U32 REFLECTION_MAP_RES = 128;
+
+// Max number of occluders to search for. JC
+const S32 MAX_OCCLUDER_COUNT = 2;
+
+extern S32 gBoxFrame;
+//extern BOOL gHideSelectedObjects;
+extern BOOL gDisplaySwapBuffers;
+extern BOOL gDebugGL;
+
+// hack counter for rendering a fixed number of frames after toggling
+// fullscreen to work around DEV-5361
+static S32 sDelayedVBOEnable = 0;
+
+BOOL gAvatarBacklight = FALSE;
+
+BOOL gDebugPipeline = FALSE;
+LLPipeline gPipeline;
+const LLMatrix4* gGLLastMatrix = NULL;
+
+LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
+LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
+LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
+LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
+LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
+LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
+LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
+LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
+LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
+LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
+LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
+LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
+LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
+LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
+LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
+LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
+LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
+LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
+LLFastTimer::DeclareTimer FTM_POOLS("Pools");
+LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
+LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
+LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
+LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
+LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
+
+
+static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
+static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
+
+//----------------------------------------
+std::string gPoolNames[] =
+{
+ // Correspond to LLDrawpool enum render type
+ "NONE",
+ "POOL_SIMPLE",
+ "POOL_GROUND",
+ "POOL_FULLBRIGHT",
+ "POOL_BUMP",
+ "POOL_TERRAIN,"
+ "POOL_SKY",
+ "POOL_WL_SKY",
+ "POOL_TREE",
+ "POOL_GRASS",
+ "POOL_INVISIBLE",
+ "POOL_AVATAR",
+ "POOL_VOIDWATER",
+ "POOL_WATER",
+ "POOL_GLOW",
+ "POOL_ALPHA"
+};
+
+void drawBox(const LLVector3& c, const LLVector3& r);
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
+
+U32 nhpo2(U32 v)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
+glh::matrix4f glh_copy_matrix(GLdouble* src)
+{
+ glh::matrix4f ret;
+ for (U32 i = 0; i < 16; i++)
+ {
+ ret.m[i] = (F32) src[i];
+ }
+ return ret;
+}
+
+glh::matrix4f glh_get_current_modelview()
+{
+ return glh_copy_matrix(gGLModelView);
+}
+
+glh::matrix4f glh_get_current_projection()
+{
+ return glh_copy_matrix(gGLProjection);
+}
+
+glh::matrix4f glh_get_last_modelview()
+{
+ return glh_copy_matrix(gGLLastModelView);
+}
+
+glh::matrix4f glh_get_last_projection()
+{
+ return glh_copy_matrix(gGLLastProjection);
+}
+
+void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst)
+{
+ for (U32 i = 0; i < 16; i++)
+ {
+ dst[i] = src.m[i];
+ }
+}
+
+void glh_set_current_modelview(const glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLModelView);
+}
+
+void glh_set_current_projection(glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLProjection);
+}
+
+glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
+{
+ glh::matrix4f ret(
+ 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
+ 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
+ 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
+ 0.f, 0.f, 0.f, 1.f);
+
+ return ret;
+}
+
+void display_update_camera();
+//----------------------------------------
+
+S32 LLPipeline::sCompiles = 0;
+
+BOOL LLPipeline::sPickAvatar = TRUE;
+BOOL LLPipeline::sDynamicLOD = TRUE;
+BOOL LLPipeline::sShowHUDAttachments = TRUE;
+BOOL LLPipeline::sRenderMOAPBeacons = FALSE;
+BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
+BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
+BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
+BOOL LLPipeline::sRenderParticleBeacons = FALSE;
+BOOL LLPipeline::sRenderSoundBeacons = FALSE;
+BOOL LLPipeline::sRenderBeacons = FALSE;
+BOOL LLPipeline::sRenderHighlight = TRUE;
+BOOL LLPipeline::sForceOldBakedUpload = FALSE;
+S32 LLPipeline::sUseOcclusion = 0;
+BOOL LLPipeline::sDelayVBUpdate = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
+BOOL LLPipeline::sDisableShaders = FALSE;
+BOOL LLPipeline::sRenderBump = TRUE;
+BOOL LLPipeline::sBakeSunlight = FALSE;
+BOOL LLPipeline::sNoAlpha = FALSE;
+BOOL LLPipeline::sUseTriStrips = TRUE;
+BOOL LLPipeline::sUseFarClip = TRUE;
+BOOL LLPipeline::sShadowRender = FALSE;
+BOOL LLPipeline::sWaterReflections = FALSE;
+BOOL LLPipeline::sRenderGlow = FALSE;
+BOOL LLPipeline::sReflectionRender = FALSE;
+BOOL LLPipeline::sImpostorRender = FALSE;
+BOOL LLPipeline::sUnderWaterRender = FALSE;
+BOOL LLPipeline::sTextureBindTest = FALSE;
+BOOL LLPipeline::sRenderFrameTest = FALSE;
+BOOL LLPipeline::sRenderAttachedLights = TRUE;
+BOOL LLPipeline::sRenderAttachedParticles = TRUE;
+BOOL LLPipeline::sRenderDeferred = FALSE;
+S32 LLPipeline::sVisibleLightCount = 0;
+F32 LLPipeline::sMinRenderSize = 0.f;
+
+
+static LLCullResult* sCull = NULL;
+
+static const U32 gl_cube_face[] =
+{
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
+};
+
+void validate_framebuffer_object();
+
+
+void addDeferredAttachments(LLRenderTarget& target)
+{
+ target.addColorAttachment(GL_RGBA); //specular
+ target.addColorAttachment(GL_RGBA); //normal+z
+}
+
+LLPipeline::LLPipeline() :
+ mBackfaceCull(FALSE),
+ mBatchCount(0),
+ mMatrixOpCount(0),
+ mTextureMatrixOps(0),
+ mMaxBatchSize(0),
+ mMinBatchSize(0),
+ mMeanBatchSize(0),
+ mTrianglesDrawn(0),
+ mNumVisibleNodes(0),
+ mVerticesRelit(0),
+ mLightingChanges(0),
+ mGeometryChanges(0),
+ mNumVisibleFaces(0),
+
+ mInitialized(FALSE),
+ mVertexShadersEnabled(FALSE),
+ mVertexShadersLoaded(0),
+ mRenderDebugFeatureMask(0),
+ mRenderDebugMask(0),
+ mOldRenderDebugMask(0),
+ mGroupQ1Locked(false),
+ mGroupQ2Locked(false),
+ mLastRebuildPool(NULL),
+ mAlphaPool(NULL),
+ mSkyPool(NULL),
+ mTerrainPool(NULL),
+ mWaterPool(NULL),
+ mGroundPool(NULL),
+ mSimplePool(NULL),
+ mFullbrightPool(NULL),
+ mInvisiblePool(NULL),
+ mGlowPool(NULL),
+ mBumpPool(NULL),
+ mWLSkyPool(NULL),
+ mLightMask(0),
+ mLightMovingMask(0),
+ mLightingDetail(0),
+ mScreenWidth(0),
+ mScreenHeight(0)
+{
+ mNoiseMap = 0;
+ mTrueNoiseMap = 0;
+ mLightFunc = 0;
+}
+
+void LLPipeline::init()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
+
+ sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+ LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
+ sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
+ sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
+
+ mInitialized = TRUE;
+
+ stop_glerror();
+
+ //create render pass pools
+ getPool(LLDrawPool::POOL_ALPHA);
+ getPool(LLDrawPool::POOL_SIMPLE);
+ getPool(LLDrawPool::POOL_GRASS);
+ getPool(LLDrawPool::POOL_FULLBRIGHT);
+ getPool(LLDrawPool::POOL_INVISIBLE);
+ getPool(LLDrawPool::POOL_BUMP);
+ getPool(LLDrawPool::POOL_GLOW);
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
+ resetFrameStats();
+
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
+ }
+
+ mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
+ mRenderDebugMask = 0; // All debug starts off
+
+ // Don't turn on ground when this is set
+ // Mac Books with intel 950s need this
+ if(!gSavedSettings.getBOOL("RenderGround"))
+ {
+ toggleRenderType(RENDER_TYPE_GROUND);
+ }
+
+ // make sure RenderPerformanceTest persists (hackity hack hack)
+ // disables non-object rendering (UI, sky, water, etc)
+ if (gSavedSettings.getBOOL("RenderPerformanceTest"))
+ {
+ gSavedSettings.setBOOL("RenderPerformanceTest", FALSE);
+ gSavedSettings.setBOOL("RenderPerformanceTest", TRUE);
+ }
+
+ mOldRenderDebugMask = mRenderDebugMask;
+
+ mBackfaceCull = TRUE;
+
+ stop_glerror();
+
+ // Enable features
+
+ LLViewerShaderMgr::instance()->setShaders();
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ mSpotLightFade[i] = 1.f;
+ }
+
+ setLightingDetail(-1);
+}
+
+LLPipeline::~LLPipeline()
+{
+
+}
+
+void LLPipeline::cleanup()
+{
+ assertInitialized();
+
+ mGroupQ1.clear() ;
+ mGroupQ2.clear() ;
+
+ for(pool_set_t::iterator iter = mPools.begin();
+ iter != mPools.end(); )
+ {
+ pool_set_t::iterator curiter = iter++;
+ LLDrawPool* poolp = *curiter;
+ if (poolp->isFacePool())
+ {
+ LLFacePool* face_pool = (LLFacePool*) poolp;
+ if (face_pool->mReferences.empty())
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+ else
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+
+ if (!mTerrainPools.empty())
+ {
+ llwarns << "Terrain Pools not cleaned up" << llendl;
+ }
+ if (!mTreePools.empty())
+ {
+ llwarns << "Tree Pools not cleaned up" << llendl;
+ }
+
+ delete mAlphaPool;
+ mAlphaPool = NULL;
+ delete mSkyPool;
+ mSkyPool = NULL;
+ delete mTerrainPool;
+ mTerrainPool = NULL;
+ delete mWaterPool;
+ mWaterPool = NULL;
+ delete mGroundPool;
+ mGroundPool = NULL;
+ delete mSimplePool;
+ mSimplePool = NULL;
+ delete mFullbrightPool;
+ mFullbrightPool = NULL;
+ delete mInvisiblePool;
+ mInvisiblePool = NULL;
+ delete mGlowPool;
+ mGlowPool = NULL;
+ delete mBumpPool;
+ mBumpPool = NULL;
+ // don't delete wl sky pool it was handled above in the for loop
+ //delete mWLSkyPool;
+ mWLSkyPool = NULL;
+
+ releaseGLBuffers();
+
+ mFaceSelectImagep = NULL;
+
+ mMovedBridge.clear();
+
+ mInitialized = FALSE;
+}
+
+//============================================================================
+
+void LLPipeline::destroyGL()
+{
+ stop_glerror();
+ unloadShaders();
+ mHighlightFaces.clear();
+
+ resetDrawOrders();
+
+ resetVertexBuffers();
+
+ releaseGLBuffers();
+
+ if (LLVertexBuffer::sEnableVBOs)
+ {
+ // render 30 frames after switching to work around DEV-5361
+ sDelayedVBOEnable = 30;
+ LLVertexBuffer::sEnableVBOs = FALSE;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
+
+void LLPipeline::resizeScreenTexture()
+{
+ LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
+ if (gPipeline.canUseVertexShaders() && assertInitialized())
+ {
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ allocateScreenBuffer(resX,resY);
+ }
+}
+
+void LLPipeline::allocatePhysicsBuffer()
+{
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY)
+ {
+ mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ if (mSampleBuffer.getWidth() == mPhysicsDisplay.getWidth() &&
+ mSampleBuffer.getHeight() == mPhysicsDisplay.getHeight())
+ {
+ mPhysicsDisplay.setSampleBuffer(&mSampleBuffer);
+ }
+ }
+}
+
+void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
+{
+ // remember these dimensions
+ mScreenWidth = resX;
+ mScreenHeight = resY;
+
+ //never use more than 4 samples for render targets
+ U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4);
+ if (gGLManager.mIsATI)
+ { //disable multisampling of render targets where ATI is involved
+ samples = 0;
+ }
+
+ U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+
+ if (res_mod > 1 && res_mod < resX && res_mod < resY)
+ {
+ resX /= res_mod;
+ resY /= res_mod;
+ }
+
+ if (gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
+ BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO");
+ bool gi = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED);
+
+ //allocate deferred rendering color buffers
+ mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ addDeferredAttachments(mDeferredScreen);
+
+ mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+
+ if (shadow_detail > 0 || ssao)
+ { //only need mDeferredLight[0] for shadows OR ssao
+ mDeferredLight[0].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+ else
+ {
+ mDeferredLight[0].release();
+ }
+
+ if (ssao)
+ { //only need mDeferredLight[1] for ssao
+ mDeferredLight[1].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+ else
+ {
+ mDeferredLight[1].release();
+ }
+
+ if (gi)
+ { //only need mDeferredLight[2] and mGIMapPost for gi
+ mDeferredLight[2].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ for (U32 i = 0; i < 2; i++)
+ {
+ mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+ }
+ else
+ {
+ mDeferredLight[2].release();
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ mGIMapPost[i].release();
+ }
+ }
+
+ F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
+
+ //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
+ U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
+
+ if (shadow_detail > 0)
+ { //allocate 4 sun shadow maps
+ for (U32 i = 0; i < 4; i++)
+ {
+ mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+ }
+ else
+ {
+ for (U32 i = 0; i < 4; i++)
+ {
+ mShadow[i].release();
+ }
+ }
+
+ U32 width = nhpo2(U32(resX*scale))/2;
+ U32 height = width;
+
+ if (shadow_detail > 1)
+ { //allocate two spot shadow maps
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
+ }
+ }
+ else
+ {
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+ }
+
+ width = nhpo2(resX)/2;
+ height = nhpo2(resY)/2;
+ mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
+ }
+ else
+ {
+ for (U32 i = 0; i < 3; i++)
+ {
+ mDeferredLight[i].release();
+ }
+ for (U32 i = 0; i < 2; i++)
+ {
+ mGIMapPost[i].release();
+ }
+ for (U32 i = 0; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+ mScreen.release();
+ mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
+ mDeferredDepth.release();
+ mEdgeMap.release();
+ mLuminanceMap.release();
+
+ mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ }
+
+ if (LLRenderTarget::sUseFBO && samples > 1)
+ {
+ mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
+ if (LLPipeline::sRenderDeferred)
+ {
+ addDeferredAttachments(mSampleBuffer);
+ mDeferredScreen.setSampleBuffer(&mSampleBuffer);
+ mEdgeMap.setSampleBuffer(&mSampleBuffer);
+ }
+
+ mScreen.setSampleBuffer(&mSampleBuffer);
+
+ stop_glerror();
+ }
+ else
+ {
+ mSampleBuffer.release();
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ { //share depth buffer between deferred targets
+ mDeferredScreen.shareDepthBuffer(mScreen);
+ for (U32 i = 0; i < 3; i++)
+ { //share stencil buffer with screen space lightmap to stencil out sky
+ if (mDeferredLight[i].getTexture(0))
+ {
+ mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
+ }
+ }
+ }
+
+ gGL.getTexUnit(0)->disable();
+
+ stop_glerror();
+
+}
+
+//static
+void LLPipeline::updateRenderDeferred()
+{
+ BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") &&
+ LLRenderTarget::sUseFBO &&
+ LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+ gSavedSettings.getBOOL("VertexShaderEnable") &&
+ gSavedSettings.getBOOL("RenderAvatarVP") &&
+ gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
+ !gUseWireframe;
+
+ sRenderDeferred = deferred;
+ if (deferred)
+ { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all
+ sRenderGlow = TRUE;
+ }
+}
+
+void LLPipeline::releaseGLBuffers()
+{
+ assertInitialized();
+
+ if (mNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mNoiseMap);
+ mNoiseMap = 0;
+ }
+
+ if (mTrueNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mTrueNoiseMap);
+ mTrueNoiseMap = 0;
+ }
+
+ if (mLightFunc)
+ {
+ LLImageGL::deleteTextures(1, &mLightFunc);
+ mLightFunc = 0;
+ }
+
+ mWaterRef.release();
+ mWaterDis.release();
+ mScreen.release();
+ mPhysicsDisplay.release();
+ mUIScreen.release();
+ mSampleBuffer.release();
+ mDeferredScreen.release();
+ mDeferredDepth.release();
+ for (U32 i = 0; i < 3; i++)
+ {
+ mDeferredLight[i].release();
+ }
+
+ mEdgeMap.release();
+ mGIMap.release();
+ mGIMapPost[0].release();
+ mGIMapPost[1].release();
+ mHighlight.release();
+ mLuminanceMap.release();
+
+ for (U32 i = 0; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].release();
+ }
+
+ LLVOAvatar::resetImpostors();
+}
+
+void LLPipeline::createGLBuffers()
+{
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
+ assertInitialized();
+
+ updateRenderDeferred();
+
+ if (LLPipeline::sWaterReflections)
+ { //water reflection texture
+ U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
+
+ mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ }
+
+ mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
+
+ stop_glerror();
+
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ if (LLPipeline::sRenderGlow)
+ { //screen space glow buffers
+ const U32 glow_res = llmax(1,
+ llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
+ }
+
+ allocateScreenBuffer(resX,resY);
+ mScreenWidth = 0;
+ mScreenHeight = 0;
+ }
+
+ if (sRenderDeferred)
+ {
+ if (!mNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ LLVector3 noise[noiseRes*noiseRes];
+
+ F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
+ for (U32 i = 0; i < noiseRes*noiseRes; ++i)
+ {
+ noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
+ noise[i].normVec();
+ noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
+ }
+
+ LLImageGL::generateTextures(1, &mNoiseMap);
+
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mTrueNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ F32 noise[noiseRes*noiseRes*3];
+ for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
+ {
+ noise[i] = ll_frand()*2.0-1.0;
+ }
+
+ LLImageGL::generateTextures(1, &mTrueNoiseMap);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mLightFunc)
+ {
+ U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+ U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
+ U8* lg = new U8[lightResX*lightResY];
+
+ for (U32 y = 0; y < lightResY; ++y)
+ {
+ for (U32 x = 0; x < lightResX; ++x)
+ {
+ //spec func
+ F32 sa = (F32) x/(lightResX-1);
+ F32 spec = (F32) y/(lightResY-1);
+ //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
+
+ //F32 sp = acosf(sa)/(1.f-spec);
+
+ sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
+ F32 a = acosf(sa*0.25f+0.75f);
+ F32 m = llmax(0.5f-spec*0.5f, 0.001f);
+ F32 t2 = tanf(a)/m;
+ t2 *= t2;
+
+ F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
+ F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
+
+ lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
+ }
+ }
+
+ LLImageGL::generateTextures(1, &mLightFunc);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+
+ delete [] lg;
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredGI"))
+ {
+ mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE);
+ addDeferredAttachments(mGIMap);
+ }
+ }
+}
+
+void LLPipeline::restoreGL()
+{
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
+ assertInitialized();
+
+ if (mVertexShadersEnabled)
+ {
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->restoreGL();
+ }
+ }
+ }
+}
+
+
+BOOL LLPipeline::canUseVertexShaders()
+{
+ if (sDisableShaders ||
+ !gGLManager.mHasVertexShader ||
+ !gGLManager.mHasFragmentShader ||
+ !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
+ (assertInitialized() && mVertexShadersLoaded != 1) )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+BOOL LLPipeline::canUseWindLightShaders() const
+{
+ return (!LLPipeline::sDisableShaders &&
+ gWLSkyProgram.mProgramObject != 0 &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
+}
+
+BOOL LLPipeline::canUseWindLightShadersOnObjects() const
+{
+ return (canUseWindLightShaders()
+ && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
+}
+
+BOOL LLPipeline::canUseAntiAliasing() const
+{
+ return TRUE;
+}
+
+void LLPipeline::unloadShaders()
+{
+ LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
+ LLViewerShaderMgr::instance()->unloadShaders();
+
+ mVertexShadersLoaded = 0;
+}
+
+void LLPipeline::assertInitializedDoError()
+{
+ llerrs << "LLPipeline used when uninitialized." << llendl;
+}
+
+//============================================================================
+
+void LLPipeline::enableShadows(const BOOL enable_shadows)
+{
+ //should probably do something here to wrangle shadows....
+}
+
+S32 LLPipeline::getMaxLightingDetail() const
+{
+ /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
+ {
+ return 3;
+ }
+ else*/
+ {
+ return 1;
+ }
+}
+
+S32 LLPipeline::setLightingDetail(S32 level)
+{
+ LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
+
+ if (level < 0)
+ {
+ if (gSavedSettings.getBOOL("RenderLocalLights"))
+ {
+ level = 1;
+ }
+ else
+ {
+ level = 0;
+ }
+ }
+ level = llclamp(level, 0, getMaxLightingDetail());
+ mLightingDetail = level;
+
+ return mLightingDetail;
+}
+
+class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ const std::set<LLViewerFetchedTexture*>& mTextures;
+
+ LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
+
+ virtual void visit(const LLOctreeNode<LLDrawable>* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
+ {
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ LLDrawInfo* params = *j;
+ LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
+ if (tex && mTextures.find(tex) != mTextures.end())
+ {
+ group->setState(LLSpatialGroup::GEOM_DIRTY);
+ }
+ }
+ }
+ }
+
+ for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ traverse(bridge->mOctree);
+ }
+ }
+};
+
+// Called when a texture changes # of channels (causes faces to move to alpha pool)
+void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
+{
+ assertInitialized();
+
+ // *TODO: This is inefficient and causes frame spikes; need a better way to do this
+ // Most of the time is spent in dirty.traverse.
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (poolp->isFacePool())
+ {
+ ((LLFacePool*) poolp)->dirtyTextures(textures);
+ }
+ }
+
+ LLOctreeDirtyTexture dirty(textures);
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ dirty.traverse(part->mOctree);
+ }
+ }
+ }
+}
+
+LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
+{
+ assertInitialized();
+
+ LLDrawPool *poolp = NULL;
+ switch( type )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ poolp = mSimplePool;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ poolp = mGrassPool;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ poolp = mFullbrightPool;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ poolp = mInvisiblePool;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ poolp = mGlowPool;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ poolp = mBumpPool;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ poolp = mAlphaPool;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ poolp = mSkyPool;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ poolp = mWaterPool;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ poolp = mGroundPool;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ poolp = mWLSkyPool;
+ break;
+
+ default:
+ llassert(0);
+ llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
+ break;
+ }
+
+ return poolp;
+}
+
+
+LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ LLDrawPool *poolp = findPool(type, tex0);
+ if (poolp)
+ {
+ return poolp;
+ }
+
+ LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
+ addPool( new_poolp );
+
+ return new_poolp;
+}
+
+
+// static
+LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ U32 type = getPoolTypeFromTE(te, imagep);
+ return gPipeline.getPool(type, imagep);
+}
+
+//static
+U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
+
+ if (!te || !imagep)
+ {
+ return 0;
+ }
+
+ bool alpha = te->getColor().mV[3] < 0.999f;
+ if (imagep)
+ {
+ alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
+ }
+
+ if (alpha)
+ {
+ return LLDrawPool::POOL_ALPHA;
+ }
+ else if ((te->getBumpmap() || te->getShiny()))
+ {
+ return LLDrawPool::POOL_BUMP;
+ }
+ else
+ {
+ return LLDrawPool::POOL_SIMPLE;
+ }
+}
+
+
+void LLPipeline::addPool(LLDrawPool *new_poolp)
+{
+ LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
+ assertInitialized();
+ mPools.insert(new_poolp);
+ addToQuickLookup( new_poolp );
+}
+
+void LLPipeline::allocDrawable(LLViewerObject *vobj)
+{
+ LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
+ LLDrawable *drawable = new LLDrawable();
+ vobj->mDrawable = drawable;
+
+ drawable->mVObjp = vobj;
+
+ //encompass completely sheared objects by taking
+ //the most extreme point possible (<1,1,0.5>)
+ drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
+ if (vobj->isOrphaned())
+ {
+ drawable->setState(LLDrawable::FORCE_INVISIBLE);
+ }
+ drawable->updateXform(TRUE);
+}
+
+
+static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
+
+void LLPipeline::unlinkDrawable(LLDrawable *drawable)
+{
+ LLFastTimer t(FTM_UNLINK);
+
+ assertInitialized();
+
+ LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
+
+ // Based on flags, remove the drawable from the queues that it's on.
+ if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST);
+ LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
+ if (iter != mMovedList.end())
+ {
+ mMovedList.erase(iter);
+ }
+ }
+
+ if (drawablep->getSpatialGroup())
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
+ if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
+ {
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+ llwarns << "Couldn't remove object from spatial group!" << llendl;
+#else
+ llerrs << "Couldn't remove object from spatial group!" << llendl;
+#endif
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
+ mLights.erase(drawablep);
+
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ if (iter->drawable == drawablep)
+ {
+ mNearbyLights.erase(iter);
+ break;
+ }
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
+ HighlightItem item(drawablep);
+ mHighlightSet.erase(item);
+
+ if (mHighlightObject == drawablep)
+ {
+ mHighlightObject = NULL;
+ }
+ }
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ mShadowSpotLight[i] = NULL;
+ }
+
+ if (mTargetShadowSpotLight[i] == drawablep)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+ }
+
+
+}
+
+U32 LLPipeline::addObject(LLViewerObject *vobj)
+{
+ LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
+
+ if (gSavedSettings.getBOOL("RenderDelayCreation"))
+ {
+ mCreateQ.push_back(vobj);
+ }
+ else
+ {
+ createObject(vobj);
+ }
+
+ return 1;
+}
+
+void LLPipeline::createObjects(F32 max_dtime)
+{
+ LLFastTimer ftm(FTM_GEO_UPDATE);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
+
+ LLTimer update_timer;
+
+ while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
+ {
+ LLViewerObject* vobj = mCreateQ.front();
+ if (!vobj->isDead())
+ {
+ createObject(vobj);
+ }
+ mCreateQ.pop_front();
+ }
+
+ //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
+ //{
+ // createObject(*iter);
+ //}
+
+ //mCreateQ.clear();
+}
+
+void LLPipeline::createObject(LLViewerObject* vobj)
+{
+ LLDrawable* drawablep = vobj->mDrawable;
+
+ if (!drawablep)
+ {
+ drawablep = vobj->createDrawable(this);
+ }
+ else
+ {
+ llerrs << "Redundant drawable creation!" << llendl;
+ }
+
+ llassert(drawablep);
+
+ if (vobj->getParent())
+ {
+ vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
+ }
+ else
+ {
+ vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
+ }
+
+ markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
+
+ if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes"))
+ {
+ // fun animated res
+ drawablep->updateXform(TRUE);
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ drawablep->setScale(LLVector3(0,0,0));
+ drawablep->makeActive();
+ }
+}
+
+
+void LLPipeline::resetFrameStats()
+{
+ assertInitialized();
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
+
+ if (mBatchCount > 0)
+ {
+ mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
+ }
+ mTrianglesDrawn = 0;
+ sCompiles = 0;
+ mVerticesRelit = 0;
+ mLightingChanges = 0;
+ mGeometryChanges = 0;
+ mNumVisibleFaces = 0;
+
+ if (mOldRenderDebugMask != mRenderDebugMask)
+ {
+ gObjectList.clearDebugText();
+ mOldRenderDebugMask = mRenderDebugMask;
+ }
+
+}
+
+//external functions for asynchronous updating
+void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
+{
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
+ drawablep->updateMove(); // returns done
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
+{
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
+ drawablep->updateMove();
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
+{
+ for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
+ iter != moved_list.end(); )
+ {
+ LLDrawable::drawable_vector_t::iterator curiter = iter++;
+ LLDrawable *drawablep = *curiter;
+ BOOL done = TRUE;
+ if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
+ {
+ done = drawablep->updateMove();
+ }
+ drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
+ if (done)
+ {
+ drawablep->clearState(LLDrawable::ON_MOVE_LIST);
+ iter = moved_list.erase(curiter);
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
+static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
+
+void LLPipeline::updateMove()
+{
+ LLFastTimer t(FTM_UPDATE_MOVE);
+ LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
+
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Retexture");
+ LLFastTimer t(ftm);
+
+ for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
+ iter != mRetexturedList.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+ if (drawablep && !drawablep->isDead())
+ {
+ drawablep->updateTexture();
+ }
+ }
+ mRetexturedList.clear();
+ }
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Moved List");
+ LLFastTimer t(ftm);
+ updateMovedList(mMovedList);
+ }
+
+ //balance octrees
+ {
+ LLFastTimer ot(FTM_OCTREE_BALANCE);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->mOctree->balance();
+ }
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Culling and occlusion testing
+/////////////////////////////////////////////////////////////////////////////
+
+//static
+F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
+{
+ LLVector3 lookAt = center - camera.getOrigin();
+ F32 dist = lookAt.length();
+
+ //ramp down distance for nearby objects
+ //shrink dist by dist/16.
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.length()/dist);
+ F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+ return radius*radius * F_PI;
+}
+
+//static
+F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera)
+{
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ LLVector4a lookAt;
+ lookAt.setSub(center, origin);
+ F32 dist = lookAt.getLength3().getF32();
+
+ //ramp down distance for nearby objects
+ //shrink dist by dist/16.
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.getLength3().getF32()/dist);
+ F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+ return radius*radius * F_PI;
+}
+
+void LLPipeline::grabReferences(LLCullResult& result)
+{
+ sCull = &result;
+}
+
+void LLPipeline::clearReferences()
+{
+ sCull = NULL;
+}
+
+void check_references(LLSpatialGroup* group, LLDrawable* drawable)
+{
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ if (drawable == *i)
+ {
+ llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
+ }
+ }
+}
+
+void check_references(LLDrawable* drawable, LLFace* face)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ if (drawable->getFace(i) == face)
+ {
+ llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+}
+
+void check_references(LLSpatialGroup* group, LLFace* face)
+{
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ check_references(drawable, face);
+ }
+}
+
+void LLPipeline::checkReferences(LLFace* face)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, face);
+ }
+
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ check_references(drawable, face);
+ }
+ }
+#endif
+}
+
+void LLPipeline::checkReferences(LLDrawable* drawable)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, drawable);
+ }
+
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+ {
+ if (drawable == *iter)
+ {
+ llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+#endif
+}
+
+void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info)
+{
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo* params = *j;
+ if (params == draw_info)
+ {
+ llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+}
+
+
+void LLPipeline::checkReferences(LLDrawInfo* draw_info)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ check_references(group, draw_info);
+ }
+ }
+#endif
+}
+
+void LLPipeline::checkReferences(LLSpatialGroup* group)
+{
+#if 0
+ if (sCull)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ if (group == *iter)
+ {
+ llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+ }
+ }
+ }
+#endif
+}
+
+
+BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
+{
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (part->visibleObjectsInFrustum(camera))
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
+{
+ const F32 X = 65536.f;
+
+ min = LLVector3(X,X,X);
+ max = LLVector3(-X,-X,-X);
+
+ U32 saved_camera_id = LLViewerCamera::sCurCameraID;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+ BOOL res = TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (!part->getVisibleExtents(camera, min, max))
+ {
+ res = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ LLViewerCamera::sCurCameraID = saved_camera_id;
+
+ return res;
+}
+
+static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
+
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep)
+{
+ LLFastTimer t(FTM_CULL);
+ LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
+
+ grabReferences(result);
+
+ sCull->clear();
+
+ BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
+ !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
+ LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ gPipeline.canUseVertexShaders() &&
+ sRenderGlow;
+
+ if (to_texture)
+ {
+ mScreen.bindTarget();
+ }
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(false, false);
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixd(gGLLastProjection);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLLastModelView);
+
+
+ LLVertexBuffer::unbind();
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+
+ //setup a clip plane in projection matrix for reflection renders (prevents flickering from occlusion culling)
+ LLViewerRegion* region = gAgent.getRegion();
+ LLPlane plane;
+
+ if (planep)
+ {
+ plane = *planep;
+ }
+ else
+ {
+ if (region)
+ {
+ LLVector3 pnorm;
+ F32 height = region->getWaterHeight();
+ if (water_clip < 0)
+ { //camera is above water, clip plane points up
+ pnorm.setVec(0,0,1);
+ plane.setVec(pnorm, -height);
+ }
+ else if (water_clip > 0)
+ { //camera is below water, clip plane points down
+ pnorm = LLVector3(0,0,-1);
+ plane.setVec(pnorm, height);
+ }
+ }
+ }
+
+ glh::matrix4f modelview = glh_get_last_modelview();
+ glh::matrix4f proj = glh_get_last_projection();
+ LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ if (water_clip != 0)
+ {
+ LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
+ camera.setUserClipPlane(plane);
+ }
+ else
+ {
+ camera.disableUserClipPlane();
+ }
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->cull(camera);
+ }
+ }
+ }
+ }
+
+ camera.disableUserClipPlane();
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
+ gSky.mVOSkyp.notNull() &&
+ gSky.mVOSkyp->mDrawable.notNull())
+ {
+ gSky.mVOSkyp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
+ gSky.updateCull();
+ stop_glerror();
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
+ !gPipeline.canUseWindLightShaders() &&
+ gSky.mVOGroundp.notNull() &&
+ gSky.mVOGroundp->mDrawable.notNull() &&
+ !LLPipeline::sWaterReflections)
+ {
+ gSky.mVOGroundp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
+ }
+
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(true, false);
+ }
+
+ if (to_texture)
+ {
+ mScreen.flush();
+ }
+}
+
+void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
+{
+ if (group->getData().empty())
+ {
+ return;
+ }
+
+ group->setVisible();
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ group->updateDistance(camera);
+ }
+
+ const F32 MINIMUM_PIXEL_AREA = 16.f;
+
+ if (group->mPixelArea < MINIMUM_PIXEL_AREA)
+ {
+ return;
+ }
+
+ if (sMinRenderSize > 0.f &&
+ llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!group->mSpatialPartition->mRenderByGroup)
+ { //render by drawable
+ sCull->pushDrawableGroup(group);
+ }
+ else
+ { //render by group
+ sCull->pushVisibleGroup(group);
+ }
+
+ mNumVisibleNodes++;
+}
+
+void LLPipeline::markOccluder(LLSpatialGroup* group)
+{
+ if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
+ {
+ LLSpatialGroup* parent = group->getParent();
+
+ if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //only mark top most occluders as active occlusion
+ sCull->pushOcclusionGroup(group);
+ group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+
+ if (parent &&
+ !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
+ parent->getElementCount() == 0 &&
+ parent->needsUpdate())
+ {
+ sCull->pushOcclusionGroup(group);
+ parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+ }
+ }
+}
+
+void LLPipeline::doOcclusion(LLCamera& camera)
+{
+ if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
+ {
+ LLVertexBuffer::unbind();
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ {
+ gGL.setColorMask(true, false, false, false);
+ }
+ else
+ {
+ gGL.setColorMask(false, false);
+ }
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ LLGLDisable cull(GL_CULL_FACE);
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->doOcclusion(&camera);
+ group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+
+ gGL.setColorMask(true, false);
+ }
+}
+
+BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
+{
+ BOOL update_complete = drawablep->updateGeometry(priority);
+ if (update_complete && assertInitialized())
+ {
+ drawablep->setState(LLDrawable::BUILT);
+ mGeometryChanges++;
+ }
+ return update_complete;
+}
+
+void LLPipeline::updateGL()
+{
+ while (!LLGLUpdate::sGLQ.empty())
+ {
+ LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
+ glu->updateGL();
+ glu->mInQ = FALSE;
+ LLGLUpdate::sGLQ.pop_front();
+ }
+}
+
+void LLPipeline::rebuildPriorityGroups()
+{
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ gMeshRepo.notifyLoadedMeshes();
+
+ mGroupQ1Locked = true;
+ // Iterate through all drawables on the priority build queue,
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
+ iter != mGroupQ1.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->rebuildGeom();
+ group->clearState(LLSpatialGroup::IN_BUILD_Q1);
+ }
+
+ mGroupQ1.clear();
+ mGroupQ1Locked = false;
+
+}
+
+void LLPipeline::rebuildGroups()
+{
+ if (mGroupQ2.empty())
+ {
+ return;
+ }
+
+ mGroupQ2Locked = true;
+ // Iterate through some drawables on the non-priority build queue
+ S32 size = (S32) mGroupQ2.size();
+ S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
+
+ S32 count = 0;
+
+ std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
+
+ LLSpatialGroup::sg_vector_t::iterator iter;
+ LLSpatialGroup::sg_vector_t::iterator last_iter = mGroupQ2.begin();
+
+ for (iter = mGroupQ2.begin();
+ iter != mGroupQ2.end() && count <= min_count; ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ last_iter = iter;
+
+ if (!group->isDead())
+ {
+ group->rebuildGeom();
+
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ count++;
+ }
+ }
+
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+ }
+
+ mGroupQ2.erase(mGroupQ2.begin(), ++last_iter);
+
+ mGroupQ2Locked = false;
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::updateGeom(F32 max_dtime)
+{
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
+ LLPointer<LLDrawable> drawablep;
+
+ LLFastTimer t(FTM_GEO_UPDATE);
+
+ assertInitialized();
+
+ if (sDelayedVBOEnable > 0)
+ {
+ if (--sDelayedVBOEnable <= 0)
+ {
+ resetVertexBuffers();
+ LLVertexBuffer::sEnableVBOs = TRUE;
+ }
+ }
+
+ // notify various object types to reset internal cost metrics, etc.
+ // for now, only LLVOVolume does this to throttle LOD changes
+ LLVOVolume::preUpdateGeom();
+
+ // Iterate through all drawables on the priority build queue,
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
+ iter != mBuildQ1.end();)
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+ if (drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
+ if (find != mBuildQ2.end())
+ {
+ mBuildQ2.erase(find);
+ }
+ }
+
+ if (updateDrawableGeom(drawablep, TRUE))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
+ mBuildQ1.erase(curiter);
+ }
+ }
+ else
+ {
+ mBuildQ1.erase(curiter);
+ }
+ }
+
+ // Iterate through some drawables on the non-priority build queue
+ S32 min_count = 16;
+ S32 size = (S32) mBuildQ2.size();
+ if (size > 1024)
+ {
+ min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
+ }
+
+ S32 count = 0;
+
+ max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
+ LLSpatialGroup* last_group = NULL;
+ LLSpatialBridge* last_bridge = NULL;
+
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
+ iter != mBuildQ2.end(); )
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+
+ LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
+ drawablep->getParent()->getSpatialBridge();
+
+ if (drawablep->getSpatialGroup() != last_group &&
+ (!last_bridge || bridge != last_bridge) &&
+ (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
+ {
+ break;
+ }
+
+ //make sure updates don't stop in the middle of a spatial group
+ //to avoid thrashing (objects are enqueued by group)
+ last_group = drawablep->getSpatialGroup();
+ last_bridge = bridge;
+
+ BOOL update_complete = TRUE;
+ if (!drawablep->isDead())
+ {
+ update_complete = updateDrawableGeom(drawablep, FALSE);
+ count++;
+ }
+ if (update_complete)
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ mBuildQ2.erase(curiter);
+ }
+ }
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
+
+ if(drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
+ llassert(root); // trying to catch a bad assumption
+ if (root && // // this test may not be needed, see above
+ root->getVObj()->isAttachment())
+ {
+ LLDrawable* rootparent = root->getParent();
+ if (rootparent) // this IS sometimes NULL
+ {
+ LLViewerObject *vobj = rootparent->getVObj();
+ llassert(vobj); // trying to catch a bad assumption
+ if (vobj) // this test may not be needed, see above
+ {
+ const LLVOAvatar* av = vobj->asAvatar();
+ if (av && av->isImpostor())
+ {
+ return;
+ }
+ }
+ }
+ }
+ sCull->pushBridge((LLSpatialBridge*) drawablep);
+ }
+ else
+ {
+ sCull->pushDrawable(drawablep);
+ }
+
+ drawablep->setVisible(camera);
+ }
+}
+
+void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
+{
+ LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
+
+ if (!drawablep)
+ {
+ //llerrs << "Sending null drawable to moved list!" << llendl;
+ return;
+ }
+
+ if (drawablep->isDead())
+ {
+ llwarns << "Marking NULL or dead drawable moved!" << llendl;
+ return;
+ }
+
+ if (drawablep->getParent())
+ {
+ //ensure that parent drawables are moved first
+ markMoved(drawablep->getParent(), damped_motion);
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ mMovedBridge.push_back(drawablep);
+ }
+ else
+ {
+ mMovedList.push_back(drawablep);
+ }
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+ if (damped_motion == FALSE)
+ {
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
+ }
+ else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
+ {
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ }
+}
+
+void LLPipeline::markShift(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
+
+ if (!drawablep || drawablep->isDead())
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
+ if (drawablep->getParent())
+ {
+ markShift(drawablep->getParent());
+ }
+ mShiftList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_SHIFT_LIST);
+ }
+}
+
+void LLPipeline::shiftObjects(const LLVector3 &offset)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
+
+ assertInitialized();
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ gDepthDirty = TRUE;
+
+ LLVector4a offseta;
+ offseta.load3(offset.mV);
+
+ for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+ iter != mShiftList.end(); iter++)
+ {
+ LLDrawable *drawablep = *iter;
+ if (drawablep->isDead())
+ {
+ continue;
+ }
+ drawablep->shiftPos(offseta);
+ drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
+ }
+ mShiftList.resize(0);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->shift(offseta);
+ }
+ }
+ }
+
+ LLHUDText::shiftAll(offset);
+ LLHUDNameTag::shiftAll(offset);
+ display_update_camera();
+}
+
+void LLPipeline::markTextured(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ mRetexturedList.insert(drawablep);
+ }
+}
+
+void LLPipeline::markGLRebuild(LLGLUpdate* glu)
+{
+ if (glu && !glu->mInQ)
+ {
+ LLGLUpdate::sGLQ.push_back(glu);
+ glu->mInQ = TRUE;
+ }
+}
+
+void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ if (group && !group->isDead() && group->mSpatialPartition)
+ {
+ if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
+ {
+ priority = TRUE;
+ }
+
+ if (priority)
+ {
+ if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
+ {
+ llassert_always(!mGroupQ1Locked);
+
+ mGroupQ1.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q1);
+
+ if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
+ {
+ LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
+ if (iter != mGroupQ2.end())
+ {
+ mGroupQ2.erase(iter);
+ }
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+ }
+ }
+ }
+ else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
+ {
+ llassert_always(!mGroupQ2Locked);
+ mGroupQ2.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q2);
+
+ }
+ }
+}
+
+void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ if (!drawablep->isState(LLDrawable::BUILT))
+ {
+ priority = TRUE;
+ }
+ if (priority)
+ {
+ if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
+ {
+ mBuildQ1.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
+ }
+ }
+ else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ mBuildQ2.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
+ }
+ if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
+ }
+ drawablep->setState(flag);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
+
+void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
+{
+ if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::END_RENDER_TYPES))
+ {
+ //clear faces from face pools
+ LLFastTimer t(FTM_RESET_DRAWORDER);
+ gPipeline.resetDrawOrders();
+ }
+
+ LLFastTimer ftm(FTM_STATESORT);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ //LLVertexBuffer::unbind();
+
+ grabReferences(result);
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ markVisible(*i, camera);
+ }
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ LLSpatialGroup* last_group = NULL;
+ for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLCullResult::bridge_list_t::iterator cur_iter = i;
+ LLSpatialBridge* bridge = *cur_iter;
+ LLSpatialGroup* group = bridge->getSpatialGroup();
+
+ if (last_group == NULL)
+ {
+ last_group = group;
+ }
+
+ if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ stateSort(bridge, camera);
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ last_group != group && last_group->changeLOD())
+ {
+ last_group->mLastUpdateDistance = last_group->mDistance;
+ }
+
+ last_group = group;
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ last_group && last_group->changeLOD())
+ {
+ last_group->mLastUpdateDistance = last_group->mDistance;
+ }
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ stateSort(group, camera);
+ }
+ }
+
+ {
+ LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
+ iter != sCull->endVisibleList(); ++iter)
+ {
+ LLDrawable *drawablep = *iter;
+ if (!drawablep->isDead())
+ {
+ stateSort(drawablep, camera);
+ }
+ }
+ }
+ {
+ LLFastTimer ftm(FTM_CLIENT_COPY);
+ LLVertexBuffer::clientCopy();
+ }
+
+ postSort(camera);
+}
+
+void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (group->changeLOD())
+ {
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawablep = *i;
+ stateSort(drawablep, camera);
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ { //avoid redundant stateSort calls
+ group->mLastUpdateDistance = group->mDistance;
+ }
+ }
+
+}
+
+void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (bridge->getSpatialGroup()->changeLOD())
+ {
+ bool force_update = false;
+ bridge->updateDistance(camera, force_update);
+ }
+}
+
+void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ if (!drawablep
+ || drawablep->isDead()
+ || !hasRenderType(drawablep->getRenderType()))
+ {
+ return;
+ }
+
+ if (LLSelectMgr::getInstance()->mHideSelectedObjects)
+ {
+ if (drawablep->getVObj().notNull() &&
+ drawablep->getVObj()->isSelected())
+ {
+ return;
+ }
+ }
+
+ if (drawablep->isAvatar())
+ { //don't draw avatars beyond render distance or if we don't have a spatial group.
+ if ((drawablep->getSpatialGroup() == NULL) ||
+ (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
+ {
+ return;
+ }
+
+ LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
+ if (!avatarp->isVisible())
+ {
+ return;
+ }
+ }
+
+ assertInitialized();
+
+ if (hasRenderType(drawablep->mRenderType))
+ {
+ if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
+ {
+ drawablep->setVisible(camera, NULL, FALSE);
+ }
+ else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
+ {
+ // clear invisible flag here to avoid single frame glitch
+ drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
+ {
+ if (!drawablep->isActive())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update);
+ }
+ else if (drawablep->isAvatar())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
+ }
+ }
+ }
+
+ if (!drawablep->getVOVolume())
+ {
+ for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
+ iter != drawablep->mFaces.end(); iter++)
+ {
+ LLFace* facep = *iter;
+
+ if (facep->hasGeometry())
+ {
+ if (facep->getPool())
+ {
+ facep->getPool()->enqueue(facep);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+
+ mNumVisibleFaces += drawablep->getNumFaces();
+}
+
+
+void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
+ LLCullResult::sg_list_t::iterator end,
+ void (*func)(LLDrawable*))
+{
+ for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
+ {
+ for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
+ {
+ func(*j);
+ }
+ }
+}
+
+void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
+{
+ forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
+ forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
+}
+
+//function for creating scripted beacons
+void renderScriptedBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderScriptedTouchBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted()
+ && vobj->flagHandleTouch())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderPhysicalBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ //&& !vobj->getParent()
+ && vobj->usePhysics())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderMOAPBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+
+ if(!vobj || vobj->isAvatar())
+ return;
+
+ BOOL beacon=FALSE;
+ U8 tecount=vobj->getNumTEs();
+ for(int x=0;x<tecount;x++)
+ {
+ if(vobj->getTE(x)->hasMedia())
+ {
+ beacon=TRUE;
+ break;
+ }
+ }
+ if(beacon==TRUE)
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 1.f, 1.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderParticleBeacons(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && vobj->isParticleSource())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderSoundHighlights(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj && vobj->isAudioSource())
+ {
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void LLPipeline::postSort(LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
+ LLFastTimer ftm(FTM_STATESORT_POSTSORT);
+
+ assertInitialized();
+
+ llpushcallstacks ;
+ //rebuild drawable geometry
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!sUseOcclusion ||
+ !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ group->rebuildGeom();
+ }
+ }
+ llpushcallstacks ;
+ //rebuild groups
+ sCull->assertDrawMapsEmpty();
+
+ rebuildPriorityGroups();
+ llpushcallstacks ;
+
+ const S32 bin_count = 1024*8;
+
+ static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
+ static U32 bin_size[bin_count];
+
+ //clear one bin per frame to avoid memory bloat
+ static S32 clear_idx = 0;
+ clear_idx = (1+clear_idx)%bin_count;
+ alpha_bins[clear_idx].clear();
+
+ for (U32 j = 0; j < bin_count; j++)
+ {
+ bin_size[j] = 0;
+ }
+
+ //build render map
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (sUseOcclusion &&
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ continue;
+ }
+
+ if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
+ { //no way this group is going to be drawable without a rebuild
+ group->rebuildGeom();
+ }
+
+ for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
+ {
+ LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
+ if (!hasRenderType(j->first))
+ {
+ continue;
+ }
+
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
+ {
+ if (sMinRenderSize > 0.f)
+ {
+ LLVector4a bounds;
+ bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
+
+ if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ else
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
+ {
+ LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
+
+ if (alpha != group->mDrawMap.end())
+ { //store alpha groups for sorting
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ if (bridge)
+ {
+ LLCamera trans_camera = bridge->transformCamera(camera);
+ group->updateDistance(trans_camera);
+ }
+ else
+ {
+ group->updateDistance(camera);
+ }
+ }
+
+ if (hasRenderType(LLDrawPool::POOL_ALPHA))
+ {
+ sCull->pushAlphaGroup(group);
+ }
+ }
+ }
+ }
+
+ if (!sShadowRender)
+ {
+ //sort by texture or bump map
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
+ {
+ if (i == LLRenderPass::PASS_BUMP)
+ {
+ std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
+ }
+ else
+ {
+ std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
+ }
+ }
+
+ std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
+ }
+ llpushcallstacks ;
+ // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
+ if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
+ {
+ if (sRenderScriptedTouchBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedTouchBeacons);
+ }
+ else
+ if (sRenderScriptedBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedBeacons);
+ }
+
+ if (sRenderPhysicalBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderPhysicalBeacons);
+ }
+
+ if(sRenderMOAPBeacons)
+ {
+ forAllVisibleDrawables(renderMOAPBeacons);
+ }
+
+ if (sRenderParticleBeacons)
+ {
+ forAllVisibleDrawables(renderParticleBeacons);
+ }
+
+ // If god mode, also show audio cues
+ if (sRenderSoundBeacons && gAudiop)
+ {
+ // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
+ LLAudioEngine::source_map::iterator iter;
+ for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
+ {
+ LLAudioSource *sourcep = iter->second;
+
+ LLVector3d pos_global = sourcep->getPositionGlobal();
+ LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
+ if (gPipeline.sRenderBeacons)
+ {
+ //pos += LLVector3(0.f, 0.f, 0.2f);
+ gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+ }
+ // now deal with highlights for all those seeable sound sources
+ forAllVisibleDrawables(renderSoundHighlights);
+ }
+ }
+ llpushcallstacks ;
+ // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
+ if (LLFloaterTelehub::renderBeacons())
+ {
+ LLFloaterTelehub::addBeacons();
+ }
+
+ if (!sShadowRender)
+ {
+ mSelectedFaces.clear();
+
+ // Draw face highlights for selected faces.
+ if (LLSelectMgr::getInstance()->getTEMode())
+ {
+ struct f : public LLSelectedTEFunctor
+ {
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ if (object->mDrawable)
+ {
+ gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+ }
+ }
+
+ //LLSpatialGroup::sNoDelete = FALSE;
+ llpushcallstacks ;
+}
+
+
+void render_hud_elements()
+{
+ LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
+ LLFastTimer t(FTM_RENDER_UI);
+ gPipeline.disableLights();
+
+ LLGLDisable fog(GL_FOG);
+ LLGLSUIDefault gls_ui;
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
+ glStencilMask(0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ gGL.color4f(1,1,1,1);
+ if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+ gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
+
+ // Draw the tracking overlays
+ LLTracker::render3D();
+
+ // Show the property lines
+ LLWorld::getInstance()->renderPropertyLines();
+ LLViewerParcelMgr::getInstance()->render();
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+
+ // Render name tags.
+ LLHUDObject::renderAll();
+ }
+ else if (gForceRenderLandFence)
+ {
+ // This is only set when not rendering the UI, for parcel snapshots
+ LLViewerParcelMgr::getInstance()->render();
+ }
+ else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ LLHUDText::renderAllHUD();
+ }
+ gGL.flush();
+}
+
+void LLPipeline::renderHighlights()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
+
+ assertInitialized();
+
+ // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
+ // Render highlighted faces.
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+ LLColor4 color(1.f, 1.f, 1.f, 0.5f);
+ LLGLEnable color_mat(GL_COLOR_MATERIAL);
+ disableLights();
+
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
+ { //draw blurry highlight image over screen
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ gGL.flush();
+ glStencilMask(0xFFFFFFFF);
+ glClearStencil(1);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ gGL.setColorMask(false, false);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
+ {
+ renderHighlight(iter->mItem->getVObj(), 1.f);
+ }
+ gGL.setColorMask(true, false);
+
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
+
+ //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ gGL.pushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ gGL.pushMatrix();
+ glLoadIdentity();
+
+ gGL.getTexUnit(0)->bind(&mHighlight);
+
+ LLVector2 tc1;
+ LLVector2 tc2;
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ gGL.begin(LLRender::TRIANGLES);
+
+ F32 scale = gSavedSettings.getF32("RenderHighlightBrightness");
+ LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor");
+ F32 thickness = gSavedSettings.getF32("RenderHighlightThickness");
+
+ for (S32 pass = 0; pass < 2; ++pass)
+ {
+ if (pass == 0)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+ }
+ else
+ {
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ for (S32 j = 0; j < 8; ++j)
+ {
+ LLVector2 tc(i-4+0.5f, j-4+0.5f);
+
+ F32 dist = 1.f-(tc.length()/sqrtf(32.f));
+ dist *= scale/64.f;
+
+ tc *= thickness;
+ tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
+ tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
+
+ gGL.color4f(color.mV[0],
+ color.mV[1],
+ color.mV[2],
+ color.mV[3]*dist);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+ }
+ }
+ }
+
+ gGL.end();
+
+ gGL.popMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ gGL.popMatrix();
+
+ //gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+ {
+ gHighlightProgram.bind();
+ gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Make sure the selection image gets downloaded and decoded
+ if (!mFaceSelectImagep)
+ {
+ mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
+ }
+ mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
+
+ U32 count = mSelectedFaces.size();
+ for (U32 i = 0; i < count; i++)
+ {
+ LLFace *facep = mSelectedFaces[i];
+ if (!facep || facep->getDrawable()->isDead())
+ {
+ llerrs << "Bad face on selection" << llendl;
+ return;
+ }
+
+ facep->renderSelected(mFaceSelectImagep, color);
+ }
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Paint 'em red!
+ color.setVec(1.f, 0.f, 0.f, 0.5f);
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+ {
+ gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
+ }
+ int count = mHighlightFaces.size();
+ for (S32 i = 0; i < count; i++)
+ {
+ LLFace* facep = mHighlightFaces[i];
+ facep->renderSelected(LLViewerTexture::sNullImagep, color);
+ }
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
+ {
+ gHighlightProgram.unbind();
+ }
+}
+
+//debug use
+U32 LLPipeline::sCurRenderPoolType = 0 ;
+
+void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ assertInitialized();
+
+ F64 saved_modelview[16];
+ F64 saved_projection[16];
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ saved_modelview[i] = gGLModelView[i];
+ saved_projection[i] = gGLProjection[i];
+ }
+ }
+
+ S32 stack_depth = 0;
+
+ if (gDebugGL)
+ {
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth);
+ }
+
+ ///////////////////////////////////////////
+ //
+ // Sync and verify GL state
+ //
+ //
+
+ stop_glerror();
+
+ LLVertexBuffer::unbind();
+
+ // Do verification of GL state
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
+ {
+ if (!verify())
+ {
+ llerrs << "Pipeline verification failed!" << llendl;
+ }
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
+
+ // Initialize lots of GL state to "safe" values
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ LLGLSPipeline gls_pipeline;
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
+
+ // Toggle backface culling for debugging
+ LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
+ // Set fog
+ BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
+ LLGLEnable fog_enable(use_fog &&
+ !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
+ gSky.updateFog(camera.getFar());
+ if (!use_fog)
+ {
+ sUnderWaterRender = FALSE;
+ }
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
+ LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
+
+ //////////////////////////////////////////////
+ //
+ // Actually render all of the geometry
+ //
+ //
+ stop_glerror();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_POOLS);
+
+ // HACK: don't calculate local lights if we're rendering the HUD!
+ // Removing this check will cause bad flickering when there are
+ // HUD elements being rendered AND the user is in flycam mode -nyx
+ if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+ }
+
+ BOOL occlude = sUseOcclusion > 1;
+ U32 cur_type = 0;
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ //debug use
+ sCurRenderPoolType = cur_type ;
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginRenderPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->render(i);
+ }
+ poolp->endRenderPass(i);
+ LLVertexBuffer::unbind();
+ if (gDebugGL)
+ {
+ check_stack_depth(stack_depth);
+ std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
+ LLGLState::checkStates(msg);
+ LLGLState::checkTextureChannels(msg);
+ LLGLState::checkClientArrays(msg);
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
+
+ LLVertexBuffer::unbind();
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ }
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+
+
+ stop_glerror();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
+
+ if (!sReflectionRender)
+ {
+ renderHighlights();
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
+ {
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLModelView[i] = saved_modelview[i];
+ gGLProjection[i] = saved_projection[i];
+ }
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+}
+
+void LLPipeline::renderGeomDeferred(LLCamera& camera)
+{
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
+
+ LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ LLFastTimer t2(FTM_POOLS);
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+ stop_glerror();
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ stop_glerror();
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ U32 cur_type = 0;
+
+ gGL.setColorMask(true, true);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderDeferred(i);
+ }
+ poolp->endDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth > 3)
+ {
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ gGL.setColorMask(true, false);
+}
+
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+{
+ LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
+ LLFastTimer t(FTM_POOLS);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+
+ gGL.setColorMask(true, false);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ BOOL occlude = LLPipeline::sUseOcclusion > 1;
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ gGL.setColorMask(true, false);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginPostDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderPostDeferred(i);
+ }
+ poolp->endPostDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth > 3)
+ {
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ }
+}
+
+void LLPipeline::renderGeomShadow(LLCamera& camera)
+{
+ LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLVertexBuffer::unbind();
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
+ {
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginShadowPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderShadow(i);
+ }
+ poolp->endShadowPass(i);
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+}
+
+
+void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
+{
+ assertInitialized();
+ S32 count = 0;
+ if (render_type == LLRender::TRIANGLE_STRIP)
+ {
+ count = index_count-2;
+ }
+ else
+ {
+ count = index_count/3;
+ }
+
+ mTrianglesDrawn += count;
+ mBatchCount++;
+ mMaxBatchSize = llmax(mMaxBatchSize, count);
+ mMinBatchSize = llmin(mMinBatchSize, count);
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ gViewerWindow->getWindow()->swapBuffers();
+ ms_sleep(16);
+ }
+}
+
+void LLPipeline::renderPhysicsDisplay()
+{
+ if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
+ {
+ return;
+ }
+
+ allocatePhysicsBuffer();
+
+ gGL.flush();
+ mPhysicsDisplay.bindTarget();
+ glClearColor(0,0,0,1);
+ gGL.setColorMask(true, true);
+ mPhysicsDisplay.clear();
+ glClearColor(0,0,0,0);
+
+ gGL.setColorMask(true, false);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderPhysicsShapes();
+ }
+ }
+ }
+ }
+
+ for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+ {
+ glPushMatrix();
+ glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ bridge->renderPhysicsShapes();
+ glPopMatrix();
+ }
+ }
+
+
+ gGL.flush();
+ mPhysicsDisplay.flush();
+}
+
+
+void LLPipeline::renderDebug()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ gGL.color4f(1,1,1,1);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ gGL.setColorMask(true, false);
+
+ bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD);
+
+ // Debug stuff.
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
+ !hud_only && hasRenderType(part->mDrawableType) )
+ {
+ part->renderDebug();
+ }
+ }
+ }
+ }
+
+ for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+ {
+ glPushMatrix();
+ glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ bridge->renderDebug();
+ glPopMatrix();
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowUploadCost"))
+ {
+ std::set<LLUUID> textures;
+ std::set<LLUUID> sculpts;
+ std::set<LLUUID> meshes;
+
+ BOOL selected = TRUE;
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ selected = FALSE;
+ }
+
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
+ for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem)
+ {
+ LLDrawable* drawable = *elem;
+ LLVOVolume* volume = drawable->getVOVolume();
+ if (volume && volume->isSelected() == selected)
+ {
+ for (U32 i = 0; i < volume->getNumTEs(); ++i)
+ {
+ LLTextureEntry* te = volume->getTE(i);
+ textures.insert(te->getID());
+ }
+
+ if (volume->isSculpted())
+ {
+ LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID();
+ if (volume->isMesh())
+ {
+ meshes.insert(sculpt_id);
+ }
+ else
+ {
+ sculpts.insert(sculpt_id);
+ }
+ }
+ }
+ }
+ }
+
+ gPipeline.mDebugTextureUploadCost = textures.size() * 10;
+ gPipeline.mDebugSculptUploadCost = sculpts.size()*10;
+
+ U32 mesh_cost = 0;
+
+ for (std::set<LLUUID>::iterator iter = meshes.begin(); iter != meshes.end(); ++iter)
+ {
+ mesh_cost += gMeshRepo.getResourceCost(*iter)*10;
+ }
+
+ gPipeline.mDebugMeshUploadCost = mesh_cost;
+ }
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLVertexBuffer::unbind();
+
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(TRUE, FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gGL.color4f(1,1,1,1);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ F32 a = 0.1f;
+
+ F32 col[] =
+ {
+ 1,0,0,a,
+ 0,1,0,a,
+ 0,0,1,a,
+ 1,0,1,a,
+
+ 1,1,0,a,
+ 0,1,1,a,
+ 1,1,1,a,
+ 1,0,1,a,
+ };
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
+ if (i > 3)
+ { //render shadow frusta as volumes
+ if (mShadowFrustPoints[i-4].empty())
+ {
+ continue;
+ }
+
+ gGL.color4fv(col+(i-4)*4);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.end();
+
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[2].mV);
+ gGL.end();
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[6].mV);
+ gGL.end();
+ }
+
+
+ if (i < 4)
+ {
+
+ //if (i == 0 || !mShadowFrustPoints[i].empty())
+ {
+ //render visible point cloud
+ gGL.flush();
+ glPointSize(8.f);
+ gGL.begin(LLRender::POINTS);
+
+ F32* c = col+i*4;
+ gGL.color3fv(c);
+
+ for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
+ {
+ gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
+
+ }
+ gGL.end();
+
+ gGL.flush();
+ glPointSize(1.f);
+
+ LLVector3* ext = mShadowExtents[i];
+ LLVector3 pos = (ext[0]+ext[1])*0.5f;
+ LLVector3 size = (ext[1]-ext[0])*0.5f;
+ drawBoxOutline(pos, size);
+
+ //render camera frustum splits as outlines
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.end();
+ }
+ }
+
+ /*gGL.flush();
+ glLineWidth(16-i*2);
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderIntersectingBBoxes(&mShadowCamera[i]);
+ }
+ }
+ }
+ }
+ gGL.flush();
+ glLineWidth(1.f);*/
+ }
+ }
+
+ if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
+ {
+ // Debug composition layers
+ F32 x, y;
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (gAgent.getRegion())
+ {
+ gGL.begin(LLRender::POINTS);
+ // Draw the composition layer for the region that I'm in.
+ for (x = 0; x <= 260; x++)
+ {
+ for (y = 0; y <= 260; y++)
+ {
+ if ((x > 255) || (y > 255))
+ {
+ gGL.color4f(1.f, 0.f, 0.f, 1.f);
+ }
+ else
+ {
+ gGL.color4f(0.f, 0.f, 1.f, 1.f);
+ }
+ F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
+ z *= 5.f;
+ z += 50.f;
+ gGL.vertex3f(x, y, z);
+ }
+ }
+ gGL.end();
+ }
+ }
+
+ if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
+ {
+ U32 count = 0;
+ U32 size = mGroupQ2.size();
+ LLColor4 col;
+
+ LLVertexBuffer::unbind();
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+
+ gGL.pushMatrix();
+ glLoadMatrixd(gGLModelView);
+ gGLLastMatrix = NULL;
+
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ if (group->isDead())
+ {
+ continue;
+ }
+
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+
+ if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
+ {
+ continue;
+ }
+
+ if (bridge)
+ {
+ gGL.pushMatrix();
+ glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ }
+
+ F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f);
+
+
+ LLVector2 c(1.f-alpha, alpha);
+ c.normVec();
+
+
+ ++count;
+ col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.5f);
+ group->drawObjectBox(col);
+
+ if (bridge)
+ {
+ gGL.popMatrix();
+ }
+ }
+
+ gGL.popMatrix();
+ }
+
+ gGL.flush();
+
+ gPipeline.renderPhysicsDisplay();
+}
+
+void LLPipeline::rebuildPools()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
+
+ assertInitialized();
+
+ S32 max_count = mPools.size();
+ pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
+ while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
+ {
+ if (iter1 == mPools.end())
+ {
+ iter1 = mPools.begin();
+ }
+ LLDrawPool* poolp = *iter1;
+
+ if (poolp->isDead())
+ {
+ mPools.erase(iter1++);
+ removeFromQuickLookup( poolp );
+ if (poolp == mLastRebuildPool)
+ {
+ mLastRebuildPool = NULL;
+ }
+ delete poolp;
+ }
+ else
+ {
+ mLastRebuildPool = poolp;
+ iter1++;
+ }
+ max_count--;
+ }
+
+ if (isAgentAvatarValid())
+ {
+ gAgentAvatarp->rebuildHUD();
+ }
+}
+
+void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
+
+ assertInitialized();
+
+ switch( new_poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ if (mSimplePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mSimplePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ if (mGrassPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate grass pool." << llendl;
+ }
+ else
+ {
+ mGrassPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ if (mFullbrightPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mFullbrightPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ if (mInvisiblePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mInvisiblePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ if (mGlowPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate glow pool." << llendl;
+ }
+ else
+ {
+ mGlowPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ if (mBumpPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate bump pool." << llendl;
+ }
+ else
+ {
+ mBumpPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ if( mAlphaPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
+ }
+ else
+ {
+ mAlphaPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ if( mSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
+ }
+ else
+ {
+ mSkyPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ if( mWaterPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
+ }
+ else
+ {
+ mWaterPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ if( mGroundPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
+ }
+ else
+ {
+ mGroundPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ if( mWLSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
+ }
+ else
+ {
+ mWLSkyPool = new_poolp;
+ }
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
+ break;
+ }
+}
+
+void LLPipeline::removePool( LLDrawPool* poolp )
+{
+ assertInitialized();
+ removeFromQuickLookup(poolp);
+ mPools.erase(poolp);
+ delete poolp;
+}
+
+void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
+{
+ assertInitialized();
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ switch( poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ llassert(mSimplePool == poolp);
+ mSimplePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ llassert(mGrassPool == poolp);
+ mGrassPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ llassert(mFullbrightPool == poolp);
+ mFullbrightPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ llassert(mInvisiblePool == poolp);
+ mInvisiblePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ llassert(mWLSkyPool == poolp);
+ mWLSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ llassert(mGlowPool == poolp);
+ mGlowPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ llassert( poolp == mBumpPool );
+ mBumpPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ llassert( poolp == mAlphaPool );
+ mAlphaPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ llassert( poolp == mSkyPool );
+ mSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ llassert( poolp == mWaterPool );
+ mWaterPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ llassert( poolp == mGroundPool );
+ mGroundPool = NULL;
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
+ break;
+ }
+}
+
+void LLPipeline::resetDrawOrders()
+{
+ assertInitialized();
+ // Iterate through all of the draw pools and rebuild them.
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ poolp->resetDrawOrders();
+ }
+}
+
+//============================================================================
+// Once-per-frame setup of hardware lights,
+// including sun/moon, avatar backlight, and up to 6 local lights
+
+void LLPipeline::setupAvatarLights(BOOL for_edit)
+{
+ assertInitialized();
+
+ if (for_edit)
+ {
+ LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
+ LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
+ LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
+ LLMatrix4 camera_rot(camera_mat.getMat3());
+ camera_rot.invert();
+ LLVector4 light_pos = light_pos_cam * camera_rot;
+
+ light_pos.normalize();
+
+ LLLightState* light = gGL.getLight(1);
+
+ mHWLightColors[1] = diffuse;
+
+ light->setDiffuse(diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setPosition(light_pos);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+ else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
+ {
+ LLVector3 opposite_pos = -1.f * mSunDir;
+ LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
+ LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
+ backlight_pos.normalize();
+
+ LLColor4 light_diffuse = mSunDiffuse;
+ LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
+ F32 max_component = 0.001f;
+ for (S32 i = 0; i < 3; i++)
+ {
+ if (backlight_diffuse.mV[i] > max_component)
+ {
+ max_component = backlight_diffuse.mV[i];
+ }
+ }
+ F32 backlight_mag;
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
+ }
+ else
+ {
+ backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
+ }
+ backlight_diffuse *= backlight_mag / max_component;
+
+ mHWLightColors[1] = backlight_diffuse;
+
+ LLLightState* light = gGL.getLight(1);
+
+ light->setPosition(backlight_pos);
+ light->setDiffuse(backlight_diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+ else
+ {
+ LLLightState* light = gGL.getLight(1);
+
+ mHWLightColors[1] = LLColor4::black;
+
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ }
+}
+
+static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
+{
+ F32 inten = light->getLightIntensity();
+ if (inten < .001f)
+ {
+ return max_dist;
+ }
+ F32 radius = light->getLightRadius();
+ BOOL selected = light->isSelected();
+ LLVector3 dpos = light->getRenderPosition() - cam_pos;
+ F32 dist2 = dpos.lengthSquared();
+ if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
+ {
+ return max_dist;
+ }
+ F32 dist = (F32) sqrt(dist2);
+ dist *= 1.f / inten;
+ dist -= radius;
+ if (selected)
+ {
+ dist -= 10000.f; // selected lights get highest priority
+ }
+ if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
+ {
+ // moving lights get a little higher priority (too much causes artifacts)
+ dist -= light->getLightRadius()*0.25f;
+ }
+ return dist;
+}
+
+void LLPipeline::calcNearbyLights(LLCamera& camera)
+{
+ assertInitialized();
+
+ if (LLPipeline::sReflectionRender)
+ {
+ return;
+ }
+
+ if (mLightingDetail >= 1)
+ {
+ // mNearbyLight (and all light_set_t's) are sorted such that
+ // begin() == the closest light and rbegin() == the farthest light
+ const S32 MAX_LOCAL_LIGHTS = 6;
+// LLVector3 cam_pos = gAgent.getCameraPositionAgent();
+ LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
+ camera.getOrigin() :
+ gAgent.getPositionAgent();
+
+ F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
+
+ // UPDATE THE EXISTING NEARBY LIGHTS
+ light_set_t cur_nearby_lights;
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ LLDrawable* drawable = light->drawable;
+ LLVOVolume* volight = drawable->getVOVolume();
+ if (!volight || !drawable->isState(LLDrawable::LIGHT))
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (light->fade <= -LIGHT_FADE_TIME)
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (!sRenderAttachedLights && volight && volight->isAttachment())
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+
+ F32 dist = calc_light_dist(volight, cam_pos, max_dist);
+ cur_nearby_lights.insert(Light(drawable, dist, light->fade));
+ }
+ mNearbyLights = cur_nearby_lights;
+
+ // FIND NEW LIGHTS THAT ARE IN RANGE
+ light_set_t new_nearby_lights;
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
+ iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
+ {
+ continue;
+ }
+ if (light->isHUDAttachment())
+ {
+ continue; // no lighting from HUD objects
+ }
+ F32 dist = calc_light_dist(light, cam_pos, max_dist);
+ if (dist >= max_dist)
+ {
+ continue;
+ }
+ if (!sRenderAttachedLights && light && light->isAttachment())
+ {
+ continue;
+ }
+ new_nearby_lights.insert(Light(drawable, dist, 0.f));
+ if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
+ {
+ new_nearby_lights.erase(--new_nearby_lights.end());
+ const Light& last = *new_nearby_lights.rbegin();
+ max_dist = last.dist;
+ }
+ }
+
+ // INSERT ANY NEW LIGHTS
+ for (light_set_t::iterator iter = new_nearby_lights.begin();
+ iter != new_nearby_lights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
+ {
+ mNearbyLights.insert(*light);
+ ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
+ }
+ else
+ {
+ // crazy cast so that we can overwrite the fade value
+ // even though gcc enforces sets as const
+ // (fade value doesn't affect sort so this is safe)
+ Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
+ if (light->dist < farthest_light->dist)
+ {
+ if (farthest_light->fade >= 0.f)
+ {
+ farthest_light->fade = -gFrameIntervalSeconds;
+ }
+ }
+ else
+ {
+ break; // none of the other lights are closer
+ }
+ }
+ }
+
+ }
+}
+
+void LLPipeline::setupHWLights(LLDrawPool* pool)
+{
+ assertInitialized();
+
+ // Ambient
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
+
+ // Light 0 = Sun or Moon (All objects)
+ {
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ mSunDir.setVec(gSky.getSunDirection());
+ mSunDiffuse.setVec(gSky.getSunDiffuseColor());
+ }
+ else
+ {
+ mSunDir.setVec(gSky.getMoonDirection());
+ mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
+ }
+
+ F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
+ if (max_color > 1.f)
+ {
+ mSunDiffuse *= 1.f/max_color;
+ }
+ mSunDiffuse.clamp();
+
+ LLVector4 light_pos(mSunDir, 0.0f);
+ LLColor4 light_diffuse = mSunDiffuse;
+ mHWLightColors[0] = light_diffuse;
+
+ LLLightState* light = gGL.getLight(0);
+ light->setPosition(light_pos);
+ light->setDiffuse(light_diffuse);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setConstantAttenuation(1.f);
+ light->setLinearAttenuation(0.f);
+ light->setQuadraticAttenuation(0.f);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+
+ // Light 1 = Backlight (for avatars)
+ // (set by enableLightsAvatar)
+
+ S32 cur_light = 2;
+
+ // Nearby lights = LIGHT 2-7
+
+ mLightMovingMask = 0;
+
+ if (mLightingDetail >= 1)
+ {
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); ++iter)
+ {
+ LLDrawable* drawable = iter->drawable;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light)
+ {
+ continue;
+ }
+ if (drawable->isState(LLDrawable::ACTIVE))
+ {
+ mLightMovingMask |= (1<<cur_light);
+ }
+
+ LLColor4 light_color = light->getLightColor();
+ light_color.mV[3] = 0.0f;
+
+ F32 fade = iter->fade;
+ if (fade < LIGHT_FADE_TIME)
+ {
+ // fade in/out light
+ if (fade >= 0.f)
+ {
+ fade = fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
+ }
+ else
+ {
+ fade = 1.f + fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
+ }
+ fade = llclamp(fade,0.f,1.f);
+ light_color *= fade;
+ }
+
+ LLVector3 light_pos(light->getRenderPosition());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = llmax(light->getLightRadius(), 0.001f);
+
+ F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[cur_light] = light_color;
+ LLLightState* light_state = gGL.getLight(cur_light);
+
+ light_state->setPosition(light_pos_gl);
+ light_state->setDiffuse(light_color);
+ light_state->setAmbient(LLColor4::black);
+ light_state->setConstantAttenuation(0.f);
+ light_state->setLinearAttenuation(linatten);
+ light_state->setQuadraticAttenuation(0.f);
+
+ if (light->isLightSpotlight() // directional (spot-)light
+ && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
+ {
+ LLVector3 spotparams = light->getSpotLightParams();
+ LLQuaternion quat = light->getRenderRotation();
+ LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
+ at_axis *= quat;
+
+ light_state->setSpotDirection(at_axis);
+ light_state->setSpotCutoff(90.f);
+ light_state->setSpotExponent(2.f);
+
+ light_state->setSpecular(LLColor4::black);
+ }
+ else // omnidirectional (point) light
+ {
+ light_state->setSpotExponent(0.f);
+ light_state->setSpotCutoff(180.f);
+
+ // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
+ const LLColor4 specular(0.f, 0.f, 0.f, 1.f);
+ light_state->setSpecular(specular);
+ }
+ cur_light++;
+ if (cur_light >= 8)
+ {
+ break; // safety
+ }
+ }
+ }
+ for ( ; cur_light < 8 ; cur_light++)
+ {
+ mHWLightColors[cur_light] = LLColor4::black;
+ LLLightState* light = gGL.getLight(cur_light);
+
+ light->setDiffuse(LLColor4::black);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ }
+ if (gAgentAvatarp &&
+ gAgentAvatarp->mSpecialRenderMode == 3)
+ {
+ LLColor4 light_color = LLColor4::white;
+ light_color.mV[3] = 0.0f;
+
+ LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = 16.f;
+
+ F32 x = 3.f;
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[2] = light_color;
+ LLLightState* light = gGL.getLight(2);
+
+ light->setPosition(light_pos_gl);
+ light->setDiffuse(light_color);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(LLColor4::black);
+ light->setQuadraticAttenuation(0.f);
+ light->setConstantAttenuation(0.f);
+ light->setLinearAttenuation(linatten);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+ }
+
+ // Init GL state
+ glDisable(GL_LIGHTING);
+ for (S32 i = 0; i < 8; ++i)
+ {
+ gGL.getLight(i)->disable();
+ }
+ mLightMask = 0;
+}
+
+void LLPipeline::enableLights(U32 mask)
+{
+ assertInitialized();
+
+ if (mLightingDetail == 0)
+ {
+ mask &= 0xf003; // sun and backlight only (and fullbright bit)
+ }
+ if (mLightMask != mask)
+ {
+ stop_glerror();
+ if (!mLightMask)
+ {
+ glEnable(GL_LIGHTING);
+ }
+ if (mask)
+ {
+ stop_glerror();
+ for (S32 i=0; i<8; i++)
+ {
+ LLLightState* light = gGL.getLight(i);
+ if (mask & (1<<i))
+ {
+ light->enable();
+ light->setDiffuse(mHWLightColors[i]);
+ }
+ else
+ {
+ light->disable();
+ light->setDiffuse(LLColor4::black);
+ }
+ }
+ stop_glerror();
+ }
+ else
+ {
+ glDisable(GL_LIGHTING);
+ }
+ stop_glerror();
+ mLightMask = mask;
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
+ stop_glerror();
+ }
+}
+
+void LLPipeline::enableLightsStatic()
+{
+ assertInitialized();
+ U32 mask = 0x01; // Sun
+ if (mLightingDetail >= 2)
+ {
+ mask |= mLightMovingMask; // Hardware moving lights
+ }
+ else
+ {
+ mask |= 0xff & (~2); // Hardware local lights
+ }
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsDynamic()
+{
+ assertInitialized();
+ U32 mask = 0xff & (~2); // Local lights
+ enableLights(mask);
+
+ if (isAgentAvatarValid() && getLightingDetail() <= 0)
+ {
+ if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
+ {
+ gPipeline.enableLightsAvatar();
+ }
+ else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
+ {
+ gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
+ }
+ }
+}
+
+void LLPipeline::enableLightsAvatar()
+{
+ U32 mask = 0xff; // All lights
+ setupAvatarLights(FALSE);
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsPreview()
+{
+ disableLights();
+
+ glEnable(GL_LIGHTING);
+ LLColor4 ambient = gSavedSettings.getColor4("PreviewAmbientColor");
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
+
+
+ LLColor4 diffuse0 = gSavedSettings.getColor4("PreviewDiffuse0");
+ LLColor4 specular0 = gSavedSettings.getColor4("PreviewSpecular0");
+ LLColor4 diffuse1 = gSavedSettings.getColor4("PreviewDiffuse1");
+ LLColor4 specular1 = gSavedSettings.getColor4("PreviewSpecular1");
+ LLColor4 diffuse2 = gSavedSettings.getColor4("PreviewDiffuse2");
+ LLColor4 specular2 = gSavedSettings.getColor4("PreviewSpecular2");
+
+ LLVector3 dir0 = gSavedSettings.getVector3("PreviewDirection0");
+ LLVector3 dir1 = gSavedSettings.getVector3("PreviewDirection1");
+ LLVector3 dir2 = gSavedSettings.getVector3("PreviewDirection2");
+
+ dir0.normVec();
+ dir1.normVec();
+ dir2.normVec();
+
+ LLVector4 light_pos(dir0, 0.0f);
+
+ LLLightState* light = gGL.getLight(0);
+
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse0);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular0);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+
+ light_pos = LLVector4(dir1, 0.f);
+
+ light = gGL.getLight(1);
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse1);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular1);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+
+ light_pos = LLVector4(dir2, 0.f);
+ light = gGL.getLight(2);
+ light->enable();
+ light->setPosition(light_pos);
+ light->setDiffuse(diffuse2);
+ light->setAmbient(LLColor4::black);
+ light->setSpecular(specular2);
+ light->setSpotExponent(0.f);
+ light->setSpotCutoff(180.f);
+}
+
+
+void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
+{
+ U32 mask = 0x2002; // Avatar backlight only, set ambient
+ setupAvatarLights(TRUE);
+ enableLights(mask);
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
+}
+
+void LLPipeline::enableLightsFullbright(const LLColor4& color)
+{
+ assertInitialized();
+ U32 mask = 0x1000; // Non-0 mask, set ambient
+ enableLights(mask);
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
+}
+
+void LLPipeline::disableLights()
+{
+ enableLights(0); // no lighting (full bright)
+}
+
+//============================================================================
+
+class LLMenuItemGL;
+class LLInvFVBridge;
+struct cat_folder_pair;
+class LLVOBranch;
+class LLVOLeaf;
+
+void LLPipeline::findReferences(LLDrawable *drawablep)
+{
+ assertInitialized();
+ if (mLights.find(drawablep) != mLights.end())
+ {
+ llinfos << "In mLights" << llendl;
+ }
+ if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
+ {
+ llinfos << "In mMovedList" << llendl;
+ }
+ if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
+ {
+ llinfos << "In mShiftList" << llendl;
+ }
+ if (mRetexturedList.find(drawablep) != mRetexturedList.end())
+ {
+ llinfos << "In mRetexturedList" << llendl;
+ }
+
+ if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
+ {
+ llinfos << "In mBuildQ1" << llendl;
+ }
+ if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
+ {
+ llinfos << "In mBuildQ2" << llendl;
+ }
+
+ S32 count;
+
+ count = gObjectList.findReferences(drawablep);
+ if (count)
+ {
+ llinfos << "In other drawables: " << count << " references" << llendl;
+ }
+}
+
+BOOL LLPipeline::verify()
+{
+ BOOL ok = assertInitialized();
+ if (ok)
+ {
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (!poolp->verify())
+ {
+ ok = FALSE;
+ }
+ }
+ }
+
+ if (!ok)
+ {
+ llwarns << "Pipeline verify failed!" << llendl;
+ }
+ return ok;
+}
+
+//////////////////////////////
+//
+// Collision detection
+//
+//
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A method to compute a ray-AABB intersection.
+ * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
+ * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
+ * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
+ *
+ * Hence this version is faster as well as more robust than the original one.
+ *
+ * Should work provided:
+ * 1) the integer representation of 0.0f is 0x00000000
+ * 2) the sign bit of the float is the most significant one
+ *
+ * Report bugs: p.terdiman@codercorner.com
+ *
+ * \param aabb [in] the axis-aligned bounding box
+ * \param origin [in] ray origin
+ * \param dir [in] ray direction
+ * \param coord [out] impact coordinates
+ * \return true if ray intersects AABB
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//#define RAYAABB_EPSILON 0.00001f
+#define IR(x) ((U32&)x)
+
+bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
+{
+ BOOL Inside = TRUE;
+ LLVector3 MinB = center - size;
+ LLVector3 MaxB = center + size;
+ LLVector3 MaxT;
+ MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
+
+ // Find candidate planes.
+ for(U32 i=0;i<3;i++)
+ {
+ if(origin.mV[i] < MinB.mV[i])
+ {
+ coord.mV[i] = MinB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ else if(origin.mV[i] > MaxB.mV[i])
+ {
+ coord.mV[i] = MaxB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ }
+
+ // Ray origin inside bounding box
+ if(Inside)
+ {
+ coord = origin;
+ return true;
+ }
+
+ // Get largest of the maxT's for final choice of intersection
+ U32 WhichPlane = 0;
+ if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
+ if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
+
+ // Check final candidate actually inside box
+ if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
+
+ for(U32 i=0;i<3;i++)
+ {
+ if(i!=WhichPlane)
+ {
+ coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
+ if (epsilon > 0)
+ {
+ if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
+ }
+ else
+ {
+ if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
+ }
+ }
+ }
+ return true; // ray hits box
+}
+
+//////////////////////////////
+//
+// Macros, functions, and inline methods from other classes
+//
+//
+
+void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
+{
+ if (drawablep && assertInitialized())
+ {
+ if (is_light)
+ {
+ mLights.insert(drawablep);
+ drawablep->setState(LLDrawable::LIGHT);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::LIGHT);
+ mLights.erase(drawablep);
+ }
+ }
+}
+
+//static
+void LLPipeline::toggleRenderType(U32 type)
+{
+ gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
+ if (type == LLPipeline::RENDER_TYPE_WATER)
+ {
+ gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
+ }
+}
+
+//static
+void LLPipeline::toggleRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ U32 bit = (1<<type);
+ if (gPipeline.hasRenderType(type))
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.toggleRenderType(type);
+}
+
+//static
+BOOL LLPipeline::hasRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ return gPipeline.hasRenderType(type);
+}
+
+// Allows UI items labeled "Hide foo" instead of "Show foo"
+//static
+BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
+{
+ S32 type = (S32)(intptr_t)data;
+ return !gPipeline.hasRenderType(type);
+}
+
+//static
+void LLPipeline::toggleRenderDebug(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ if (gPipeline.hasRenderDebugMask(bit))
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.mRenderDebugMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugMask(bit);
+}
+
+//static
+void LLPipeline::toggleRenderDebugFeature(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ gPipeline.mRenderDebugFeatureMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugFeatureMask(bit);
+}
+
+void LLPipeline::setRenderDebugFeatureControl(U32 bit, bool value)
+{
+ if (value)
+ {
+ gPipeline.mRenderDebugFeatureMask |= bit;
+ }
+ else
+ {
+ gPipeline.mRenderDebugFeatureMask &= !bit;
+ }
+}
+
+// static
+void LLPipeline::setRenderScriptedBeacons(BOOL val)
+{
+ sRenderScriptedBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedBeacons(void*)
+{
+ sRenderScriptedBeacons = !sRenderScriptedBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedBeacons(void*)
+{
+ return sRenderScriptedBeacons;
+}
+
+// static
+void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
+{
+ sRenderScriptedTouchBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
+{
+ sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
+{
+ return sRenderScriptedTouchBeacons;
+}
+
+// static
+void LLPipeline::setRenderMOAPBeacons(BOOL val)
+{
+ sRenderMOAPBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderMOAPBeacons(void*)
+{
+ sRenderMOAPBeacons = !sRenderMOAPBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderMOAPBeacons(void*)
+{
+ return sRenderMOAPBeacons;
+}
+
+// static
+void LLPipeline::setRenderPhysicalBeacons(BOOL val)
+{
+ sRenderPhysicalBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderPhysicalBeacons(void*)
+{
+ sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderPhysicalBeacons(void*)
+{
+ return sRenderPhysicalBeacons;
+}
+
+// static
+void LLPipeline::setRenderParticleBeacons(BOOL val)
+{
+ sRenderParticleBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderParticleBeacons(void*)
+{
+ sRenderParticleBeacons = !sRenderParticleBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderParticleBeacons(void*)
+{
+ return sRenderParticleBeacons;
+}
+
+// static
+void LLPipeline::setRenderSoundBeacons(BOOL val)
+{
+ sRenderSoundBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderSoundBeacons(void*)
+{
+ sRenderSoundBeacons = !sRenderSoundBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderSoundBeacons(void*)
+{
+ return sRenderSoundBeacons;
+}
+
+// static
+void LLPipeline::setRenderBeacons(BOOL val)
+{
+ sRenderBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderBeacons(void*)
+{
+ sRenderBeacons = !sRenderBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderBeacons(void*)
+{
+ return sRenderBeacons;
+}
+
+// static
+void LLPipeline::setRenderHighlights(BOOL val)
+{
+ sRenderHighlight = val;
+}
+
+// static
+void LLPipeline::toggleRenderHighlights(void*)
+{
+ sRenderHighlight = !sRenderHighlight;
+}
+
+// static
+BOOL LLPipeline::getRenderHighlights(void*)
+{
+ return sRenderHighlight;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ LLVector3 local_end = end;
+
+ LLVector3 position;
+
+ sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ if ((j == LLViewerRegion::PARTITION_VOLUME) ||
+ (j == LLViewerRegion::PARTITION_BRIDGE) ||
+ (j == LLViewerRegion::PARTITION_TERRAIN) ||
+ (j == LLViewerRegion::PARTITION_TREE) ||
+ (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ local_end = position;
+ }
+ }
+ }
+ }
+ }
+
+ if (!sPickAvatar)
+ {
+ //save hit info in case we need to restore
+ //due to attachment override
+ LLVector3 local_normal;
+ LLVector3 local_binormal;
+ LLVector2 local_texcoord;
+ S32 local_face_hit = -1;
+
+ if (face_hit)
+ {
+ local_face_hit = *face_hit;
+ }
+ if (tex_coord)
+ {
+ local_texcoord = *tex_coord;
+ }
+ if (bi_normal)
+ {
+ local_binormal = *bi_normal;
+ }
+ if (normal)
+ {
+ local_normal = *normal;
+ }
+
+ const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
+
+ //check against avatars
+ sPickAvatar = TRUE;
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ if (!drawable ||
+ !drawable->getVObj()->isAttachment() ||
+ (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
+ { //avatar overrides if previously hit drawable is not an attachment or
+ //attachment is far enough away from detected intersection
+ drawable = hit;
+ local_end = position;
+ }
+ else
+ { //prioritize attachments over avatars
+ position = local_end;
+
+ if (face_hit)
+ {
+ *face_hit = local_face_hit;
+ }
+ if (tex_coord)
+ {
+ *tex_coord = local_texcoord;
+ }
+ if (bi_normal)
+ {
+ *bi_normal = local_binormal;
+ }
+ if (normal)
+ {
+ *normal = local_normal;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //check all avatar nametags (silly, isn't it?)
+ for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end();
+ ++iter)
+ {
+ LLVOAvatar* av = (LLVOAvatar*) *iter;
+ if (av->mNameText.notNull()
+ && av->mNameText->lineSegmentIntersect(start, local_end, position))
+ {
+ drawable = av->mDrawable;
+ local_end = position;
+ }
+ }
+
+ if (intersection)
+ {
+ *intersection = position;
+ }
+
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ BOOL toggle = FALSE;
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ toggle = TRUE;
+ }
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
+ if (part)
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ }
+ }
+
+ if (toggle)
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+ }
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
+{
+ if (vobj)
+ {
+ LLViewerRegion* region = vobj->getRegion();
+ if (region)
+ {
+ return region->getSpatialPartition(vobj->getPartitionType());
+ }
+ }
+ return NULL;
+}
+
+
+void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
+{
+ if (!drawable || drawable->isDead())
+ {
+ return;
+ }
+
+ for (S32 i = 0; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+ facep->clearVertexBuffer();
+ }
+}
+
+void LLPipeline::resetVertexBuffers()
+{
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->resetVertexBuffers();
+ }
+ }
+ }
+
+ resetDrawOrders();
+
+ gSky.resetVertexBuffers();
+
+ if (LLVertexBuffer::sGLCount > 0)
+ {
+ LLVertexBuffer::cleanupClass();
+ }
+
+ //delete all name pool caches
+ LLGLNamePool::cleanupPools();
+
+ if (LLVertexBuffer::sGLCount > 0)
+ {
+ llwarns << "VBO wipe failed." << llendl;
+ }
+
+ if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sStreamVBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sDynamicVBOPool.mNameList.empty())
+ {
+ llwarns << "VBO name pool cleanup failed." << llendl;
+ }
+
+ LLVertexBuffer::unbind();
+
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+ LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
+ LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
+ LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
+ sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
+ sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
+ LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
+}
+
+void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
+{
+ LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
+ assertInitialized();
+ glLoadMatrixd(gGLModelView);
+ gGLLastMatrix = NULL;
+ mSimplePool->pushBatches(type, mask);
+ glLoadMatrixd(gGLModelView);
+ gGLLastMatrix = NULL;
+}
+
+void apply_cube_face_rotation(U32 face)
+{
+ switch (face)
+ {
+ case 0:
+ glRotatef(90.f, 0, 1, 0);
+ glRotatef(180.f, 1, 0, 0);
+ break;
+ case 2:
+ glRotatef(-90.f, 1, 0, 0);
+ break;
+ case 4:
+ glRotatef(180.f, 0, 1, 0);
+ glRotatef(180.f, 0, 0, 1);
+ break;
+ case 1:
+ glRotatef(-90.f, 0, 1, 0);
+ glRotatef(180.f, 1, 0, 0);
+ break;
+ case 3:
+ glRotatef(90, 1, 0, 0);
+ break;
+ case 5:
+ glRotatef(180, 0, 0, 1);
+ break;
+ }
+}
+
+void validate_framebuffer_object()
+{
+ GLenum status;
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE:
+ //framebuffer OK, no error.
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Missing Attachment." << llendl;
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Attachment." << llendl;
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ /* choose different formats */
+ llerrs << "Framebuffer unsupported." << llendl;
+ break;
+ default:
+ llerrs << "Unknown framebuffer status." << llendl;
+ break;
+ }
+}
+
+void LLPipeline::bindScreenToTexture()
+{
+
+}
+
+static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
+
+void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
+{
+ LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
+ if (!(gPipeline.canUseVertexShaders() &&
+ sRenderGlow))
+ {
+ return;
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ assertInitialized();
+
+ if (gUseWireframe)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+
+ U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+
+ LLVector2 tc1(0,0);
+ LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
+ (F32) gViewerWindow->getWorldViewHeightRaw()*2);
+
+ if (res_mod > 1)
+ {
+ tc2 /= (F32) res_mod;
+ }
+
+ LLFastTimer ftm(FTM_RENDER_BLOOM);
+ gGL.color4f(1,1,1,1);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ enableLightsFullbright(LLColor4(1,1,1,1));
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ gGL.setColorMask(true, true);
+ glClearColor(0,0,0,0);
+
+ /*if (for_snapshot)
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[1]);
+ {
+ //LLGLEnable stencil(GL_STENCIL_TEST);
+ //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
+ //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ //LLGLDisable blend(GL_BLEND);
+
+ // If the snapshot is constructed from tiles, calculate which
+ // tile we're in.
+
+ //from LLViewerCamera::setPerpsective
+ if (zoom_factor > 1.f)
+ {
+ int pos_y = subfield / llceil(zoom_factor);
+ int pos_x = subfield - (pos_y*llceil(zoom_factor));
+ F32 size = 1.f/zoom_factor;
+
+ tc1.set(pos_x*size, pos_y*size);
+ tc2 = tc1 + LLVector2(size,size);
+ }
+ else
+ {
+ tc2.set(1,1);
+ }
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.color4f(1,1,1,1);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,1);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(1,-1);
+
+ gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+ gGL.vertex2f(1,1);
+
+ gGL.end();
+
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ gGL.flush();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ return;
+ }*/
+
+ {
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[2].bindTarget();
+ mGlow[2].clear();
+ }
+
+ gGlowExtractProgram.bind();
+ F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f);
+ F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
+ F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
+ LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
+ LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
+ gGlowExtractProgram.uniform1f("minLuminance", minLum);
+ gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha);
+ gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
+ gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
+ gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount);
+ LLGLEnable blend_on(GL_BLEND);
+ LLGLEnable test(GL_ALPHA_TEST);
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->disable();
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
+ gGL.getTexUnit(0)->bind(&mScreen);
+
+ gGL.color4f(1,1,1,1);
+ gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
+ mGlow[2].flush();
+ }
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ // power of two between 1 and 1024
+ U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
+ const U32 glow_res = llmax(1,
+ llmin(1024, 1 << glowResPow));
+
+ S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2;
+ F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res;
+ // Use half the glow width if we have the res set to less than 9 so that it looks
+ // almost the same in either case.
+ if (glowResPow < 9)
+ {
+ delta *= 0.5f;
+ }
+ F32 strength = gSavedSettings.getF32("RenderGlowStrength");
+
+ gGlowProgram.bind();
+ gGlowProgram.uniform1f("glowStrength", strength);
+
+ for (S32 i = 0; i < kernel; i++)
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[i%2].bindTarget();
+ mGlow[i%2].clear();
+ }
+
+ if (i == 0)
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[2]);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
+ }
+
+ if (i%2 == 0)
+ {
+ gGlowProgram.uniform2f("glowDelta", delta, 0);
+ }
+ else
+ {
+ gGlowProgram.uniform2f("glowDelta", 0, delta);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ mGlow[i%2].flush();
+ }
+
+ gGlowProgram.unbind();
+
+ if (LLRenderTarget::sUseFBO)
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+ gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+ gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+ gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+ tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(),
+ (F32) gViewerWindow->getWorldViewHeightRaw());
+
+ gGL.flush();
+
+ LLVertexBuffer::unbind();
+
+ if (LLPipeline::sRenderDeferred && !LLViewerCamera::getInstance()->cameraUnderWater())
+ {
+ LLGLSLShader* shader = &gDeferredPostProgram;
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ shader = &gDeferredGIFinalProgram;
+ }
+
+ LLGLDisable blend(GL_BLEND);
+ bindDeferredShader(*shader);
+
+ //depth of field focal plane calculations
+
+ static F32 current_distance = 16.f;
+ static F32 start_distance = 16.f;
+ static F32 transition_time = 1.f;
+
+ LLVector3 focus_point;
+
+ LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject();
+ if (obj && obj->mDrawable && obj->isSelected())
+ {
+ S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace();
+ if (obj && obj->mDrawable)
+ {
+ LLFace* face = obj->mDrawable->getFace(face_idx);
+ if (face)
+ {
+ focus_point = face->getPositionAgent();
+ }
+ }
+ }
+
+ if (focus_point.isExactlyZero())
+ {
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ focus_point = gDebugRaycastIntersection;
+ }
+ else if (gAgentCamera.cameraMouselook())
+ {
+ gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
+ NULL,
+ &focus_point);
+ }
+ else
+ {
+ LLViewerObject* obj = gAgentCamera.getFocusObject();
+ if (obj)
+ {
+ focus_point = LLVector3(gAgentCamera.getFocusGlobal()-gAgent.getRegion()->getOriginGlobal());
+ }
+ else
+ {
+ focus_point = gDebugRaycastIntersection;
+ }
+ }
+ }
+
+ LLVector3 eye = LLViewerCamera::getInstance()->getOrigin();
+ F32 target_distance = 16.f;
+ if (!focus_point.isExactlyZero())
+ {
+ target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point-eye);
+ }
+
+ if (transition_time >= 1.f &&
+ fabsf(current_distance-target_distance)/current_distance > 0.01f)
+ { //large shift happened, interpolate smoothly to new target distance
+ transition_time = 0.f;
+ start_distance = current_distance;
+ }
+ else if (transition_time < 1.f)
+ { //currently in a transition, continue interpolating
+ transition_time += 1.f/gSavedSettings.getF32("CameraFocusTransitionTime")*gFrameIntervalSeconds;
+ transition_time = llmin(transition_time, 1.f);
+
+ F32 t = cosf(transition_time*F_PI+F_PI)*0.5f+0.5f;
+ current_distance = start_distance + (target_distance-start_distance)*t;
+ }
+ else
+ { //small or no change, just snap to target distance
+ current_distance = target_distance;
+ }
+
+ //convert to mm
+ F32 subject_distance = current_distance*1000.f;
+ F32 fnumber = gSavedSettings.getF32("CameraFNumber");
+ F32 default_focal_length = gSavedSettings.getF32("CameraFocalLength");
+
+ if (LLToolMgr::getInstance()->inBuildMode() || !gSavedSettings.getBOOL("RenderDepthOfField"))
+ { //squish focal length when in build mode (or if DoF is disabled) so DoF doesn't make editing objects difficult
+ default_focal_length = 5.f;
+ }
+
+ F32 fov = LLViewerCamera::getInstance()->getView();
+
+ const F32 default_fov = gSavedSettings.getF32("CameraFieldOfView") * F_PI/180.f;
+ //const F32 default_aspect_ratio = gSavedSettings.getF32("CameraAspectRatio");
+
+ //F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight();
+
+ F32 dv = 2.f*default_focal_length * tanf(default_fov/2.f);
+ //F32 dh = 2.f*default_focal_length * tanf(default_fov*default_aspect_ratio/2.f);
+
+ F32 focal_length = dv/(2*tanf(fov/2.f));
+
+ //F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle);
+
+ // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f))
+ // where N = fnumber
+ // s2 = dot distance
+ // s1 = subject distance
+ // f = focal length
+ //
+
+ F32 blur_constant = focal_length*focal_length/(fnumber*(subject_distance-focal_length));
+ blur_constant /= 1000.f; //convert to meters for shader
+ F32 magnification = focal_length/(subject_distance-focal_length);
+
+ shader->uniform1f("focal_distance", -subject_distance/1000.f);
+ shader->uniform1f("blur_constant", blur_constant);
+ shader->uniform1f("tan_pixel_angle", tanf(1.f/LLDrawable::sCurPixelAngle));
+ shader->uniform1f("magnification", magnification);
+
+ S32 channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mScreen.bindTexture(0, channel);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+ //channel = shader->enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ //if (channel > -1)
+ //{
+ //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ //}
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(*shader);
+ }
+ else
+ {
+ if (res_mod > 1)
+ {
+ tc2 /= (F32) res_mod;
+ }
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
+ buff->allocateBuffer(3,0,TRUE);
+
+ LLStrider<LLVector3> v;
+ LLStrider<LLVector2> uv1;
+ LLStrider<LLVector2> uv2;
+
+ buff->getVertexStrider(v);
+ buff->getTexCoord0Strider(uv1);
+ buff->getTexCoord1Strider(uv2);
+
+ uv1[0] = LLVector2(0, 0);
+ uv1[1] = LLVector2(0, 2);
+ uv1[2] = LLVector2(2, 0);
+
+ uv2[0] = LLVector2(0, 0);
+ uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
+ uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
+
+ v[0] = LLVector3(-1,-1,0);
+ v[1] = LLVector3(-1,3,0);
+ v[2] = LLVector3(3,-1,0);
+
+ buff->setBuffer(0);
+
+ LLGLDisable blend(GL_BLEND);
+
+ //tex unit 0
+ gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
+
+ gGL.getTexUnit(0)->bind(&mGlow[1]);
+ gGL.getTexUnit(1)->activate();
+ gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
+
+
+ //tex unit 1
+ gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+
+ gGL.getTexUnit(1)->bind(&mScreen);
+ gGL.getTexUnit(1)->activate();
+
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ buff->setBuffer(mask);
+ buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
+
+ gGL.getTexUnit(1)->disable();
+ gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ gGL.getTexUnit(0)->activate();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+ }
+
+ if (LLRenderTarget::sUseFBO)
+ { //copy depth buffer from mScreen to framebuffer
+ LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
+ 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES))
+ {
+ LLVector2 tc1(0,0);
+ LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
+ (F32) gViewerWindow->getWorldViewHeightRaw()*2);
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.color4f(1,1,1,0.75f);
+
+ gGL.getTexUnit(0)->bind(&mPhysicsDisplay);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+ gGL.flush();
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
+
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
+{
+ LLFastTimer t(FTM_BIND_DEFERRED);
+
+ if (noise_map == 0xFFFFFFFF)
+ {
+ noise_map = mNoiseMap;
+ }
+
+ LLGLState::checkTextureChannels();
+
+ shader.bind();
+ S32 channel = 0;
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(0,channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (gi_source)
+ {
+ BOOL has_gi = FALSE;
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(3, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(3, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gGL.getTexUnit(channel)->bind(gi_source, TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+
+ glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
+
+ stop_glerror();
+ }
+
+ if (has_gi)
+ {
+ F32 range_x = llmin(mGIRange.mV[0], 1.f);
+ F32 range_y = llmin(mGIRange.mV[1], 1.f);
+
+ LLVector2 scale(range_x,range_y);
+
+ LLVector2 kern[25];
+
+ for (S32 i = 0; i < 5; ++i)
+ {
+ for (S32 j = 0; j < 5; ++j)
+ {
+ S32 idx = i*5+j;
+ kern[idx].mV[0] = (i-2)*0.5f;
+ kern[idx].mV[1] = (j-2)*0.5f;
+ kern[idx].scaleVec(scale);
+ }
+ }
+
+ shader.uniform2fv("gi_kern", 25, (F32*) kern);
+ shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m);
+ shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m);
+ shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m);
+ shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m);
+ }
+ }
+
+ /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(3, channel);
+ }*/
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+
+ glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
+
+ stop_glerror();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f inv_proj = projection.inverse();
+
+ shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m);
+ shader.uniform4f("viewport", (F32) gGLViewport[0],
+ (F32) gGLViewport[1],
+ (F32) gGLViewport[2],
+ (F32) gGLViewport[3]);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ }
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[light_index].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+ if (channel > -1)
+ {
+ mGlow[1].bindTexture(0, channel);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ gi_source->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mEdgeMap.bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[1].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[2].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ stop_glerror();
+
+ F32 mat[16*6];
+ for (U32 i = 0; i < 16; i++)
+ {
+ mat[i] = mSunShadowMatrix[0].m[i];
+ mat[i+16] = mSunShadowMatrix[1].m[i];
+ mat[i+32] = mSunShadowMatrix[2].m[i];
+ mat[i+48] = mSunShadowMatrix[3].m[i];
+ mat[i+64] = mSunShadowMatrix[4].m[i];
+ mat[i+80] = mSunShadowMatrix[5].m[i];
+ }
+
+ shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat);
+ shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat);
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->enable(channel);
+ cube_map->bind();
+ F64* m = gGLModelView;
+
+
+ F32 mat[] = { m[0], m[1], m[2],
+ m[4], m[5], m[6],
+ m[8], m[9], m[10] };
+
+ shader.uniform3fv("env_mat[0]", 3, mat);
+ shader.uniform3fv("env_mat", 3, mat);
+ }
+ }
+
+ shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV);
+ shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
+ shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise"));
+ shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize"));
+
+ shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale"));
+ shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale"));
+
+ F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor");
+ shader.uniform1f("ssao_factor", ssao_factor);
+ shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor);
+
+ LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect");
+ F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
+ F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
+ // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
+ // value factor, and scales remainder by saturation factor
+ F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
+ matrix_nondiag, matrix_diag, matrix_nondiag,
+ matrix_nondiag, matrix_nondiag, matrix_diag};
+ shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
+
+ F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+ F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+
+ shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+ shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
+ shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error);
+ shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error);
+ shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset"));
+ shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias"));
+
+ shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
+ shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
+ shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
+ shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail"));
+ shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange"));
+ shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness"));
+ shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance"));
+ shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight"));
+ shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+ shader.uniform1f("gi_sample_width", mGILightRadius);
+ shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise"));
+ shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation"));
+ shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance"));
+ shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight());
+ shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight());
+ shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff"));
+ shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff"));
+
+
+ if (shader.getUniformLocation("norm_mat") >= 0)
+ {
+ glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
+ shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
+static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
+static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
+static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
+static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
+static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
+static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
+static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
+static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
+static LLFastTimer::DeclareTimer FTM_POST("Post");
+
+
+void LLPipeline::renderDeferredLighting()
+{
+ if (!sCull)
+ {
+ return;
+ }
+
+ {
+ LLFastTimer ftm(FTM_RENDER_DEFERRED);
+
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ LLGLEnable multisample(gSavedSettings.getU32("RenderFSAASamples") > 0 ? GL_MULTISAMPLE_ARB : 0);
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ //ati doesn't seem to love actually using the stencil buffer on FBO's
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ gGL.setColorMask(true, true);
+
+ //draw a cube around every light
+ LLVertexBuffer::unbind();
+
+ LLGLEnable cull(GL_CULL_FACE);
+ LLGLEnable blend(GL_BLEND);
+
+ glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+
+ F32 vert[] =
+ {
+ -1,1,
+ -1,-3,
+ 3,1,
+ };
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+ glColor3f(1,1,1);
+
+ {
+ setupHWLights(NULL); //to set mSunDir;
+ LLVector4 dir(mSunDir, 0.f);
+ glh::vec4f tc(dir.mV);
+ mat.mult_matrix_vec(tc);
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
+ }
+
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0)
+ {
+ mDeferredLight[0].bindTarget();
+ { //paint shadow/SSAO light map (direct lighting lightmap)
+ LLFastTimer ftm(FTM_SUN_SHADOW);
+ bindDeferredShader(gDeferredSunProgram, 0);
+
+ glClearColor(1,1,1,1);
+ mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+
+ const U32 slice = 32;
+ F32 offset[slice*3];
+ for (U32 i = 0; i < 4; i++)
+ {
+ for (U32 j = 0; j < 8; j++)
+ {
+ glh::vec3f v;
+ v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+ v.normalize();
+ inv_trans.mult_matrix_vec(v);
+ v.normalize();
+ offset[(i*8+j)*3+0] = v.v[0];
+ offset[(i*8+j)*3+1] = v.v[2];
+ offset[(i*8+j)*3+2] = v.v[1];
+ }
+ }
+
+ gDeferredSunProgram.uniform3fv("offset", slice, offset);
+ gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ unbindDeferredShader(gDeferredSunProgram);
+ }
+ mDeferredLight[0].flush();
+ }
+
+ { //global illumination specific block (still experimental)
+ if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
+ gSavedSettings.getBOOL("RenderDeferredGI"))
+ {
+ LLFastTimer ftm(FTM_EDGE_DETECTION);
+ //generate edge map
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ {
+ gDeferredEdgeProgram.bind();
+ mEdgeMap.bindTarget();
+ bindDeferredShader(gDeferredEdgeProgram);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gDeferredEdgeProgram);
+ mEdgeMap.flush();
+ }
+ }
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ { //get luminance map from previous frame's light map
+ LLGLEnable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ //static F32 fade = 1.f;
+
+ {
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gLuminanceGatherProgram.bind();
+ gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+ mLuminanceMap.bindTarget();
+ bindDeferredShader(gLuminanceGatherProgram);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gLuminanceGatherProgram);
+ mLuminanceMap.flush();
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ }
+ }
+
+ { //paint noisy GI map (bounce lighting lightmap)
+ LLFastTimer ftm(FTM_GI_TRACE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ mGIMapPost[0].bindTarget();
+
+ bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gDeferredGIProgram);
+ mGIMapPost[0].flush();
+ }
+
+ U32 pass_count = 0;
+ if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
+ {
+ pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128);
+ }
+
+ for (U32 i = 0; i < pass_count; ++i)
+ { //gather/soften indirect lighting map
+ LLFastTimer ftm(FTM_GI_GATHER);
+ bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap);
+ F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f);
+ gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f);
+ gDeferredPostGIProgram.uniform1f("kern_scale", blur_size);
+ gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+
+ mGIMapPost[1].bindTarget();
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ mGIMapPost[1].flush();
+ unbindDeferredShader(gDeferredPostGIProgram);
+ bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap);
+ mGIMapPost[0].bindTarget();
+
+ gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ stop_glerror();
+ }
+ mGIMapPost[0].flush();
+ unbindDeferredShader(gDeferredPostGIProgram);
+ }
+ }
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+ { //soften direct lighting lightmap
+ LLFastTimer ftm(FTM_SOFTEN_SHADOW);
+ //blur lightmap
+ mDeferredLight[1].bindTarget();
+
+ glClearColor(1,1,1,1);
+ mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ bindDeferredShader(gDeferredBlurLightProgram);
+
+ LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
+ const U32 kern_length = 4;
+ F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+ F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
+
+ // sample symmetrically with the middle sample falling exactly on 0.0
+ F32 x = 0.f;
+
+ LLVector3 gauss[32]; // xweight, yweight, offset
+
+ for (U32 i = 0; i < kern_length; i++)
+ {
+ gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+ gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+ gauss[i].mV[2] = x;
+ x += 1.f;
+ }
+
+ gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+ gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
+ gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+ gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ mDeferredLight[1].flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+
+ bindDeferredShader(gDeferredBlurLightProgram, 1);
+ mDeferredLight[0].bindTarget();
+
+ gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+ mDeferredLight[0].flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+ }
+
+ stop_glerror();
+ glPopMatrix();
+ stop_glerror();
+ glMatrixMode(GL_MODELVIEW);
+ stop_glerror();
+ glPopMatrix();
+ stop_glerror();
+
+ //copy depth and stencil from deferred screen
+ //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[1].bindTarget();
+ // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky
+ glClearColor(0,0,0,0);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+ }
+ else
+ {
+ mScreen.bindTarget();
+ // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
+ glClearColor(0,0,0,0);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredAtmospheric"))
+ { //apply sunlight contribution
+ LLFastTimer ftm(FTM_ATMOSPHERICS);
+ bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]);
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ //full screen blit
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
+ unbindDeferredShader(gDeferredSoftenProgram);
+ }
+
+ { //render sky
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ gPipeline.pushRenderTypeMask();
+
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::END_RENDER_TYPES);
+
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ gPipeline.popRenderTypeMask();
+ }
+
+ BOOL render_local = gSavedSettings.getBOOL("RenderLocalLights");
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[1].flush();
+ mDeferredLight[2].bindTarget();
+ mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (render_local)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+ std::list<LLVector4> fullscreen_lights;
+ LLDrawable::drawable_list_t spot_lights;
+ LLDrawable::drawable_list_t fullscreen_spot_lights;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+
+ std::list<LLVector4> light_colors;
+
+ LLVertexBuffer::unbind();
+
+ F32 v[24];
+ glVertexPointer(3, GL_FLOAT, 0, v);
+
+ {
+ bindDeferredShader(gDeferredLightProgram);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+ if (!volume)
+ {
+ continue;
+ }
+
+ if (volume->isAttachment())
+ {
+ if (!sRenderAttachedLights)
+ {
+ continue;
+ }
+ }
+
+
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
+ F32 s = volume->getLightRadius()*1.5f;
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ if (col.magVecSquared() < 0.001f)
+ {
+ continue;
+ }
+
+ if (s <= 0.001f)
+ {
+ continue;
+ }
+
+ LLVector4a sa;
+ sa.splat(s);
+ if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
+ {
+ continue;
+ }
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
+ v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
+ v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
+ v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
+
+ v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+ v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+ v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+ v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+ if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
+ camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
+ camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
+ camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
+ camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
+ camera->getOrigin().mV[2] < c[2] - s - 0.2f)
+ { //draw box if camera is outside box
+ if (render_local)
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ fullscreen_spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+ light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+ }
+ }
+ unbindDeferredShader(gDeferredLightProgram);
+ }
+
+ if (!spot_lights.empty())
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ bindDeferredShader(gDeferredSpotLightProgram);
+
+ gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector4a center;
+ center.load3(drawablep->getPositionAgent().mV);
+ const F32* c = center.getF32ptr();
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
+ v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
+ v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
+ v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
+
+ v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+ v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+ v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+ v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_BYTE, get_box_fan_indices_ptr(camera, center));
+ }
+ gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredSpotLightProgram);
+ }
+
+ {
+ bindDeferredShader(gDeferredMultiLightProgram);
+
+ LLGLDepthTest depth(GL_FALSE);
+
+ //full screen blit
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ U32 count = 0;
+
+ const U32 max_count = 8;
+ LLVector4 light[max_count];
+ LLVector4 col[max_count];
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+
+ F32 far_z = 0.f;
+
+ while (!fullscreen_lights.empty())
+ {
+ LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
+ light[count] = fullscreen_lights.front();
+ fullscreen_lights.pop_front();
+ col[count] = light_colors.front();
+ light_colors.pop_front();
+
+ far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
+
+ count++;
+ if (count == max_count || fullscreen_lights.empty())
+ {
+ gDeferredMultiLightProgram.uniform1i("light_count", count);
+ gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
+ gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
+ gDeferredMultiLightProgram.uniform1f("far_z", far_z);
+ far_z = 0.f;
+ count = 0;
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ }
+ }
+
+ unbindDeferredShader(gDeferredMultiLightProgram);
+
+ bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector3 center = drawablep->getPositionAgent();
+ F32* c = center.mV;
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ }
+
+ gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+ }
+
+ gGL.setColorMask(true, true);
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[2].flush();
+
+ mScreen.bindTarget();
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ { //mix various light maps (local, sun, gi)
+ LLFastTimer ftm(FTM_POST);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]);
+
+ gDeferredPostProgram.bind();
+
+ LLVertexBuffer::unbind();
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+ glColor3f(1,1,1);
+
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ unbindDeferredShader(gDeferredPostProgram);
+ }
+ }
+ }
+
+ { //render non-deferred geometry (alpha, fullbright, glow)
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_GLOW,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_GLOW,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ END_RENDER_TYPES);
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ popRenderTypeMask();
+ }
+
+ {
+ //render highlights, etc.
+ renderHighlights();
+ mHighlightFaces.clear();
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ }
+
+ mScreen.flush();
+
+}
+
+void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+{
+ //construct frustum
+ LLVOVolume* volume = drawablep->getVOVolume();
+ LLVector3 params = volume->getSpotLightParams();
+
+ F32 fov = params.mV[0];
+ F32 focus = params.mV[1];
+
+ LLVector3 pos = drawablep->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+ LLVector3 scale = volume->getScale();
+
+ //get near clip plane
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = pos+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ //matrix from volume space to agent space
+ LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+
+ glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
+ glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+
+ glh::matrix4f screen_to_light = light_to_screen.inverse();
+
+ F32 s = volume->getLightRadius()*1.5f;
+ F32 near_clip = dist;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = s+dist-scale.mV[VZ];
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh::vec3f p1(0, 0, -(near_clip+0.01f));
+ glh::vec3f p2(0, 0, -(near_clip+1.f));
+
+ glh::vec3f screen_origin(0, 0, 0);
+
+ light_to_screen.mult_matrix_vec(p1);
+ light_to_screen.mult_matrix_vec(p2);
+ light_to_screen.mult_matrix_vec(screen_origin);
+
+ glh::vec3f n = p2-p1;
+ n.normalize();
+
+ F32 proj_range = far_clip - near_clip;
+ glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
+ screen_to_light = trans * light_proj * screen_to_light;
+ shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m);
+ shader.uniform1f("proj_near", near_clip);
+ shader.uniform3fv("proj_p", 1, p1.v);
+ shader.uniform3fv("proj_n", 1, n.v);
+ shader.uniform3fv("proj_origin", 1, screen_origin.v);
+ shader.uniform1f("proj_range", proj_range);
+ shader.uniform1f("proj_ambiance", params.mV[2]);
+ S32 s_idx = -1;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ s_idx = i;
+ }
+ }
+
+ shader.uniform1i("proj_shadow_idx", s_idx);
+
+ if (s_idx >= 0)
+ {
+ shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]);
+ }
+ else
+ {
+ shader.uniform1f("shadow_fade", 1.f);
+ }
+
+ {
+ LLDrawable* potential = drawablep;
+ //determine if this is a good light for casting shadows
+ F32 m_pri = volume->getSpotLightPriority();
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ F32 pri = 0.f;
+
+ if (mTargetShadowSpotLight[i].notNull())
+ {
+ pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
+ }
+
+ if (m_pri > pri)
+ {
+ LLDrawable* temp = mTargetShadowSpotLight[i];
+ mTargetShadowSpotLight[i] = potential;
+ potential = temp;
+ m_pri = pri;
+ }
+ }
+ }
+
+ LLViewerTexture* img = volume->getLightTexture();
+
+ S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ if (channel > -1 && img)
+ {
+ gGL.getTexUnit(channel)->bind(img);
+
+ F32 lod_range = logf(img->getWidth())/logf(2.f);
+
+ shader.uniform1f("proj_focus", focus);
+ shader.uniform1f("proj_lod", lod_range);
+ shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+ }
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+{
+ stop_glerror();
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+ shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
+
+ S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->disable();
+ }
+ }
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->activate();
+ shader.unbind();
+
+ LLGLState::checkTextureChannels();
+}
+
+inline float sgn(float a)
+{
+ if (a > 0.0F) return (1.0F);
+ if (a < 0.0F) return (-1.0F);
+ return (0.0F);
+}
+
+void LLPipeline::generateWaterReflection(LLCamera& camera_in)
+{
+ if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ BOOL skip_avatar_update = FALSE;
+ if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+ {
+ skip_avatar_update = TRUE;
+ }
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
+ }
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ LLCamera camera = camera_in;
+ camera.setFar(camera.getFar()*0.87654321f);
+ LLPipeline::sReflectionRender = TRUE;
+
+ gPipeline.pushRenderTypeMask();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f mat;
+
+ stop_glerror();
+ LLPlane plane;
+
+ F32 height = gAgent.getRegion()->getWaterHeight();
+ F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
+ F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
+
+ //plane params
+ LLVector3 pnorm;
+ F32 pd;
+
+ S32 water_clip = 0;
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //camera is above water, clip plane points up
+ pnorm.setVec(0,0,1);
+ pd = -height;
+ plane.setVec(pnorm, pd);
+ water_clip = -1;
+ }
+ else
+ { //camera is below water, clip plane points down
+ pnorm = LLVector3(0,0,-1);
+ pd = height;
+ plane.setVec(pnorm, pd);
+ water_clip = 1;
+ }
+
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //generate planar reflection map
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glClearColor(0,0,0,0);
+ mWaterRef.bindTarget();
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
+ gGL.setColorMask(true, true);
+ mWaterRef.clear();
+ gGL.setColorMask(true, false);
+
+ mWaterRef.getViewport(gGLViewport);
+
+ stop_glerror();
+
+ glPushMatrix();
+
+ mat.set_scale(glh::vec3f(1,1,-1));
+ mat.set_translate(glh::vec3f(0,0,height*2.f));
+
+ glh::matrix4f current = glh_get_current_modelview();
+
+ mat = current * mat;
+
+ glh_set_current_modelview(mat);
+ glLoadMatrixf(mat.m);
+
+ LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
+
+ glh::matrix4f inv_mat = mat.inverse();
+
+ glh::vec3f origin(0,0,0);
+ inv_mat.mult_matrix_vec(origin);
+
+ camera.setOrigin(origin.v);
+
+ glCullFace(GL_FRONT);
+
+ static LLCullResult ref_result;
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
+ {
+ //initial sky pass (no user clip plane)
+ { //mask out everything but the sky
+ gPipeline.pushRenderTypeMask();
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
+ static LLCullResult result;
+ updateCull(camera, result);
+ stateSort(camera, result);
+
+ renderGeom(camera, TRUE);
+
+ gPipeline.popRenderTypeMask();
+ }
+
+ gPipeline.pushRenderTypeMask();
+
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
+ S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
+ if (detail > 0)
+ { //mask out selected geometry based on reflection detail
+ if (detail < 4)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
+ if (detail < 3)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ if (detail < 2)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
+ }
+ }
+ }
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ LLGLDisable cull(GL_CULL_FACE);
+ updateCull(camera, ref_result, -water_clip, &plane);
+ stateSort(camera, ref_result);
+ }
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
+ {
+ if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+ {
+ gPipeline.grabReferences(ref_result);
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ renderGeom(camera);
+ }
+ }
+
+ gPipeline.popRenderTypeMask();
+ }
+ glCullFace(GL_BACK);
+ glPopMatrix();
+ mWaterRef.flush();
+ glh_set_current_modelview(current);
+ }
+
+ camera.setOrigin(camera_in.getOrigin());
+ //render distortion map
+ static BOOL last_update = TRUE;
+ if (last_update)
+ {
+ camera.setFar(camera_in.getFar());
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ END_RENDER_TYPES);
+ stop_glerror();
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
+
+ if (LLPipeline::sUnderWaterRender)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ END_RENDER_TYPES);
+ }
+ LLViewerCamera::updateFrustumPlanes(camera);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLColor4& col = LLDrawPoolWater::sWaterFogColor;
+ glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+ mWaterDis.bindTarget();
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ mWaterDis.getViewport(gGLViewport);
+
+ if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ //clip out geometry on the same side of water as the camera
+ mat = glh_get_current_modelview();
+ LLPlane plane(-pnorm, -(pd+pad));
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ static LLCullResult result;
+ updateCull(camera, result, water_clip, &plane);
+ stateSort(camera, result);
+
+ gGL.setColorMask(true, true);
+ mWaterDis.clear();
+ gGL.setColorMask(true, false);
+
+ renderGeom(camera);
+ }
+
+ LLPipeline::sUnderWaterRender = FALSE;
+ mWaterDis.flush();
+ }
+ last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
+
+ LLRenderTarget::unbindTarget();
+
+ LLPipeline::sReflectionRender = FALSE;
+
+ if (!LLRenderTarget::sUseFBO)
+ {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ glClearColor(0.f, 0.f, 0.f, 0.f);
+ gViewerWindow->setup3DViewport();
+ gPipeline.popRenderTypeMask();
+ LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
+ LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
+ LLPlane npnorm(-pnorm, -pd);
+ LLViewerCamera::getInstance()->setUserClipPlane(npnorm);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+ }
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ }
+}
+
+glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
+{
+ glh::matrix4f ret;
+
+ LLVector3 dirN;
+ LLVector3 upN;
+ LLVector3 lftN;
+
+ lftN = dir % up;
+ lftN.normVec();
+
+ upN = lftN % dir;
+ upN.normVec();
+
+ dirN = dir;
+ dirN.normVec();
+
+ ret.m[ 0] = lftN[0];
+ ret.m[ 1] = upN[0];
+ ret.m[ 2] = -dirN[0];
+ ret.m[ 3] = 0.f;
+
+ ret.m[ 4] = lftN[1];
+ ret.m[ 5] = upN[1];
+ ret.m[ 6] = -dirN[1];
+ ret.m[ 7] = 0.f;
+
+ ret.m[ 8] = lftN[2];
+ ret.m[ 9] = upN[2];
+ ret.m[10] = -dirN[2];
+ ret.m[11] = 0.f;
+
+ ret.m[12] = -(lftN*pos);
+ ret.m[13] = -(upN*pos);
+ ret.m[14] = dirN*pos;
+ ret.m[15] = 1.f;
+
+ return ret;
+}
+
+glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
+{
+ glh::matrix4f ret;
+ ret.m[ 0] = 2/(max[0]-min[0]);
+ ret.m[ 4] = 0;
+ ret.m[ 8] = 0;
+ ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
+
+ ret.m[ 1] = 0;
+ ret.m[ 5] = 2/(max[1]-min[1]);
+ ret.m[ 9] = 0;
+ ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
+
+ ret.m[ 2] = 0;
+ ret.m[ 6] = 0;
+ ret.m[10] = 2/(max[2]-min[2]);
+ ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
+
+ ret.m[ 3] = 0;
+ ret.m[ 7] = 0;
+ ret.m[11] = 0;
+ ret.m[15] = 1;
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
+static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
+static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
+
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
+{
+ LLFastTimer t(FTM_SHADOW_RENDER);
+
+ //clip out geometry on the same side of water as the camera
+ S32 occlude = LLPipeline::sUseOcclusion;
+ if (!use_occlusion)
+ {
+ LLPipeline::sUseOcclusion = 0;
+ }
+ LLPipeline::sShadowRender = TRUE;
+
+ U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY };
+ LLGLEnable cull(GL_CULL_FACE);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.bind();
+ }
+
+ updateCull(shadow_cam, result);
+ stateSort(shadow_cam, result);
+
+ //generate shadow map
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(proj.m);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixd(gGLModelView);
+
+ stop_glerror();
+ gGLLastMatrix = NULL;
+
+ {
+ //LLGLDepthTest depth(GL_TRUE);
+ //glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ glColor4f(1,1,1,1);
+
+ stop_glerror();
+
+ gGL.setColorMask(false, false);
+
+ //glCullFace(GL_FRONT);
+
+ LLVertexBuffer::unbind();
+
+ {
+ LLFastTimer ftm(FTM_SHADOW_SIMPLE);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->disable();
+ for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+ {
+ renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+ }
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ }
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ renderGeomShadow(shadow_cam);
+ gDeferredShadowProgram.bind();
+ }
+ else
+ {
+ renderGeomShadow(shadow_cam);
+ }
+
+ {
+ LLFastTimer ftm(FTM_SHADOW_ALPHA);
+ LLGLEnable test(GL_ALPHA_TEST);
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
+ renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
+ glColor4f(1,1,1,1);
+ renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ }
+
+ //glCullFace(GL_BACK);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(shadow_cam);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ }
+
+ gGL.setColorMask(true, true);
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ gGLLastMatrix = NULL;
+
+ LLPipeline::sUseOcclusion = occlude;
+ LLPipeline::sShadowRender = FALSE;
+}
+
+static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
+BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
+{
+ LLFastTimer t(FTM_VISIBLE_CLOUD);
+ //get point cloud of intersection of frust and min, max
+
+ if (getVisibleExtents(camera, min, max))
+ {
+ return FALSE;
+ }
+
+ //get set of planes on bounding box
+ LLPlane bp[] = {
+ LLPlane(min, LLVector3(-1,0,0)),
+ LLPlane(min, LLVector3(0,-1,0)),
+ LLPlane(min, LLVector3(0,0,-1)),
+ LLPlane(max, LLVector3(1,0,0)),
+ LLPlane(max, LLVector3(0,1,0)),
+ LLPlane(max, LLVector3(0,0,1))};
+
+ //potential points
+ std::vector<LLVector3> pp;
+
+ //add corners of AABB
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
+
+ //add corners of camera frustum
+ for (U32 i = 0; i < 8; i++)
+ {
+ pp.push_back(camera.mAgentFrustum[i]);
+ }
+
+
+ //bounding box line segments
+ U32 bs[] =
+ {
+ 0,1,
+ 1,3,
+ 3,2,
+ 2,0,
+
+ 4,5,
+ 5,7,
+ 7,6,
+ 6,4,
+
+ 0,4,
+ 1,5,
+ 3,7,
+ 2,6
+ };
+
+ for (U32 i = 0; i < 12; i++)
+ { //for each line segment in bounding box
+ for (U32 j = 0; j < 6; j++)
+ { //for each plane in camera frustum
+ const LLPlane& cp = camera.getAgentPlane(j);
+ const LLVector3& v1 = pp[bs[i*2+0]];
+ const LLVector3& v2 = pp[bs[i*2+1]];
+ LLVector3 n;
+ cp.getVector3(n);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ //camera frustum line segments
+ const U32 fs[] =
+ {
+ 0,1,
+ 1,2,
+ 2,3,
+ 3,0,
+
+ 4,5,
+ 5,6,
+ 6,7,
+ 7,4,
+
+ 0,4,
+ 1,5,
+ 2,6,
+ 3,7
+ };
+
+ LLVector3 center = (max+min)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+
+ for (U32 i = 0; i < 12; i++)
+ {
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLVector3& v1 = pp[fs[i*2+0]+8];
+ const LLVector3& v2 = pp[fs[i*2+1]+8];
+ const LLPlane& cp = bp[j];
+ LLVector3 n;
+ cp.getVector3(n);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
+ max+LLVector3(0.05f,0.05f,0.05f) };
+
+ for (U32 i = 0; i < pp.size(); ++i)
+ {
+ bool found = true;
+
+ const F32* p = pp[i].mV;
+
+ for (U32 j = 0; j < 3; ++j)
+ {
+ if (p[j] < ext[0].mV[j] ||
+ p[j] > ext[1].mV[j])
+ {
+ found = false;
+ break;
+ }
+ }
+
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLPlane& cp = camera.getAgentPlane(j);
+ F32 dist = cp.dist(pp[i]);
+ if (dist > 0.05f) //point is above some plane, not contained
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ fp.push_back(pp[i]);
+ }
+ }
+
+ if (fp.empty())
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc)
+{
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3)
+ {
+ return;
+ }
+
+ LLVector3 up;
+
+ //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV);
+
+ if (lightDir.mV[2] > 0.5f)
+ {
+ up = LLVector3(1,0,0);
+ }
+ else
+ {
+ up = LLVector3(0, 0, 1);
+ }
+
+
+ F32 gi_range = gSavedSettings.getF32("RenderGIRange");
+
+ U32 res = mGIMap.getWidth();
+
+ F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f);
+
+ //set radius to range at which distance attenuation of incoming photons is near 0
+
+ F32 lrad = sqrtf(1.f/(atten*0.01f));
+
+ F32 lrange = lrad+gi_range*0.5f;
+
+ LLVector3 pad(lrange,lrange,lrange);
+
+ glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up);
+
+ LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f);
+
+ glh::vec3f scp(cp.mV);
+ view.mult_matrix_vec(scp);
+ cp.setVec(scp.v);
+
+ F32 pix_width = lrange/(res*0.5f);
+
+ //move cp to the nearest pix_width
+ for (U32 i = 0; i < 3; i++)
+ {
+ cp.mV[i] = llround(cp.mV[i], pix_width);
+ }
+
+ LLVector3 min = cp-pad;
+ LLVector3 max = cp+pad;
+
+ //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point
+ mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res;
+ mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res;
+ mGILightRadius = lrad/lrange*0.5f;
+
+ glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+
+ LLCamera sun_cam = camera;
+
+ glh::matrix4f eye_view = glh_get_current_modelview();
+
+ //get eye space to camera space matrix
+ mGIMatrix = view*eye_view.inverse();
+ mGINormalMatrix = mGIMatrix.inverse().transpose();
+ mGIInvProj = proj.inverse();
+ mGIMatrixProj = proj*mGIMatrix;
+
+ //translate and scale to [0,1]
+ glh::matrix4f trans(.5f, 0.f, 0.f, .5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ mGIMatrixProj = trans*mGIMatrixProj;
+
+ glh_set_current_modelview(view);
+ glh_set_current_projection(proj);
+
+ LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE);
+
+ sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+ static LLCullResult result;
+
+ pushRenderTypeMask();
+
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ END_RENDER_TYPES);
+
+
+
+ S32 occlude = LLPipeline::sUseOcclusion;
+ //LLPipeline::sUseOcclusion = 0;
+ LLPipeline::sShadowRender = TRUE;
+
+ //only render large objects into GI map
+ sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize");
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE;
+ mGIMap.bindTarget();
+
+ F64 last_modelview[16];
+ F64 last_projection[16];
+ for (U32 i = 0; i < 16; i++)
+ {
+ last_modelview[i] = gGLLastModelView[i];
+ last_projection[i] = gGLLastProjection[i];
+ gGLLastModelView[i] = mGIModelview.m[i];
+ gGLLastProjection[i] = mGIProjection.m[i];
+ }
+
+ sun_cam.setOrigin(0.f, 0.f, 0.f);
+ updateCull(sun_cam, result);
+ stateSort(sun_cam, result);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = last_modelview[i];
+ gGLLastProjection[i] = last_projection[i];
+ }
+
+ mGIProjection = proj;
+ mGIModelview = view;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ //generate GI map
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(proj.m);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(view.m);
+
+ stop_glerror();
+ gGLLastMatrix = NULL;
+
+ mGIMap.clear();
+
+ {
+ //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+ renderGeomDeferred(camera);
+ }
+
+ mGIMap.flush();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ gGLLastMatrix = NULL;
+
+ LLPipeline::sUseOcclusion = occlude;
+ LLPipeline::sShadowRender = FALSE;
+ sMinRenderSize = 0.f;
+
+ popRenderTypeMask();
+
+}
+
+void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
+{
+ if (obj && obj->getVolume())
+ {
+ for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
+ {
+ renderHighlight(*iter, fade);
+ }
+
+ LLDrawable* drawable = obj->mDrawable;
+ if (drawable)
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ if (face)
+ {
+ face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
+ }
+ }
+ }
+ }
+}
+
+void LLPipeline::generateHighlight(LLCamera& camera)
+{
+ //render highlighted object as white into offscreen render target
+ if (mHighlightObject.notNull())
+ {
+ mHighlightSet.insert(HighlightItem(mHighlightObject));
+ }
+
+ if (!mHighlightSet.empty())
+ {
+ F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime");
+
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ mHighlight.bindTarget();
+ disableLights();
+ gGL.setColorMask(true, true);
+ mHighlight.clear();
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
+ {
+ std::set<HighlightItem>::iterator cur_iter = iter++;
+
+ if (cur_iter->mItem.isNull())
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+
+ if (cur_iter->mItem == mHighlightObject)
+ {
+ cur_iter->incrFade(transition);
+ }
+ else
+ {
+ cur_iter->incrFade(-transition);
+ if (cur_iter->mFade <= 0.f)
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+ }
+
+ renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
+ }
+
+ mHighlight.flush();
+ gGL.setColorMask(true, false);
+ gViewerWindow->setup3DViewport();
+ }
+}
+
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+ if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0)
+ {
+ return;
+ }
+
+ F64 last_modelview[16];
+ F64 last_projection[16];
+ for (U32 i = 0; i < 16; i++)
+ { //store last_modelview of world camera
+ last_modelview[i] = gGLLastModelView[i];
+ last_projection[i] = gGLLastProjection[i];
+ }
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ END_RENDER_TYPES);
+
+ gGL.setColorMask(false, false);
+
+ //get sun view matrix
+
+ //store current projection/modelview matrix
+ glh::matrix4f saved_proj = glh_get_current_projection();
+ glh::matrix4f saved_view = glh_get_current_modelview();
+ glh::matrix4f inv_view = saved_view.inverse();
+
+ glh::matrix4f view[6];
+ glh::matrix4f proj[6];
+
+ //clip contains parallel split distances for 3 splits
+ LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
+
+ //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
+
+ //far clip on last split is minimum of camera view distance and 128
+ mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
+
+ clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
+ mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
+
+ //currently used for amount to extrude frusta corners for constructing shadow frusta
+ LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
+ //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+
+ //put together a universal "near clip" plane for shadow frusta
+ LLPlane shadow_near_clip;
+ {
+ LLVector3 p = gAgent.getPositionAgent();
+ p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f;
+ shadow_near_clip.setVec(p, mSunDir);
+ }
+
+ LLVector3 lightDir = -mSunDir;
+ lightDir.normVec();
+
+ glh::vec3f light_dir(lightDir.mV);
+
+ //create light space camera matrix
+
+ LLVector3 at = lightDir;
+
+ LLVector3 up = camera.getAtAxis();
+
+ if (fabsf(up*lightDir) > 0.75f)
+ {
+ up = camera.getUpAxis();
+ }
+
+ /*LLVector3 left = up%at;
+ up = at%left;*/
+
+ up.normVec();
+ at.normVec();
+
+
+ LLCamera main_camera = camera;
+
+ F32 near_clip = 0.f;
+ {
+ //get visible point cloud
+ std::vector<LLVector3> fp;
+
+ main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
+
+ LLVector3 min,max;
+ getVisiblePointCloud(main_camera,min,max,fp);
+
+ if (fp.empty())
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[0] = main_camera;
+ mShadowExtents[0][0] = min;
+ mShadowExtents[0][1] = max;
+
+ mShadowFrustPoints[0].clear();
+ mShadowFrustPoints[1].clear();
+ mShadowFrustPoints[2].clear();
+ mShadowFrustPoints[3].clear();
+ }
+ popRenderTypeMask();
+ return;
+ }
+
+ generateGI(camera, lightDir, fp);
+
+ //get good split distances for frustum
+ for (U32 i = 0; i < fp.size(); ++i)
+ {
+ glh::vec3f v(fp[i].mV);
+ saved_view.mult_matrix_vec(v);
+ fp[i].setVec(v.v);
+ }
+
+ min = fp[0];
+ max = fp[0];
+
+ //get camera space bounding box
+ for (U32 i = 1; i < fp.size(); ++i)
+ {
+ update_min_max(min, max, fp[i]);
+ }
+
+ near_clip = -max.mV[2];
+ F32 far_clip = -min.mV[2]*2.f;
+
+ //far_clip = llmin(far_clip, 128.f);
+ far_clip = llmin(far_clip, camera.getFar());
+
+ F32 range = far_clip-near_clip;
+
+ LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent");
+
+ F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
+
+ da = powf(da, split_exp.mV[2]);
+
+
+ F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ F32 x = (F32)(i+1)/4.f;
+ x = powf(x, sxp);
+ mSunClipPlanes.mV[i] = near_clip+range*x;
+ }
+ }
+
+ // convenience array of 4 near clip plane distances
+ F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
+
+ for (S32 j = 0; j < 4; j++)
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustPoints[j].clear();
+ }
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
+
+ //restore render matrices
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ LLVector3 eye = camera.getOrigin();
+
+ //camera used for shadow cull/render
+ LLCamera shadow_cam;
+
+ //create world space camera frustum for this split
+ shadow_cam = camera;
+ shadow_cam.setFar(16.f);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ LLVector3* frust = shadow_cam.mAgentFrustum;
+
+ LLVector3 pn = shadow_cam.getAtAxis();
+
+ LLVector3 min, max;
+
+ //construct 8 corners of split frustum section
+ for (U32 i = 0; i < 4; i++)
+ {
+ LLVector3 delta = frust[i+4]-eye;
+ delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
+ delta.normVec();
+ F32 dp = delta*pn;
+ frust[i] = eye + (delta*dist[j]*0.95f)/dp;
+ frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
+ }
+
+ shadow_cam.calcAgentFrustumPlanes(frust);
+ shadow_cam.mFrustumCornerDist = 0.f;
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[j] = shadow_cam;
+ }
+
+ std::vector<LLVector3> fp;
+
+ if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
+ {
+ //no possible shadow receivers
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = LLVector3();
+ mShadowExtents[j][1] = LLVector3();
+ mShadowCamera[j+4] = shadow_cam;
+ }
+
+ mShadow[j].bindTarget();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mShadow[j].clear();
+ }
+ mShadow[j].flush();
+
+ mShadowError.mV[j] = 0.f;
+ mShadowFOV.mV[j] = 0.f;
+
+ continue;
+ }
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = min;
+ mShadowExtents[j][1] = max;
+ mShadowFrustPoints[j] = fp;
+ }
+
+
+ //find a good origin for shadow projection
+ LLVector3 origin;
+
+ //get a temporary view projection
+ view[j] = look(camera.getOrigin(), lightDir, -up);
+
+ std::vector<LLVector3> wpf;
+
+ for (U32 i = 0; i < fp.size(); i++)
+ {
+ glh::vec3f p = glh::vec3f(fp[i].mV);
+ view[j].mult_matrix_vec(p);
+ wpf.push_back(LLVector3(p.v));
+ }
+
+ min = wpf[0];
+ max = wpf[0];
+
+ for (U32 i = 0; i < fp.size(); ++i)
+ { //get AABB in camera space
+ update_min_max(min, max, wpf[i]);
+ }
+
+ // Construct a perspective transform with perspective along y-axis that contains
+ // points in wpf
+ //Known:
+ // - far clip plane
+ // - near clip plane
+ // - points in frustum
+ //Find:
+ // - origin
+
+ //get some "interesting" points of reference
+ LLVector3 center = (min+max)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+ LLVector3 near_center = center;
+ near_center.mV[1] += size.mV[1]*2.f;
+
+
+ //put all points in wpf in quadrant 0, reletive to center of min/max
+ //get the best fit line using least squares
+ F32 bfm = 0.f;
+ F32 bfb = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ wpf[i] -= center;
+ wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
+ wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
+ }
+
+ if (!wpf.empty())
+ {
+ F32 sx = 0.f;
+ F32 sx2 = 0.f;
+ F32 sy = 0.f;
+ F32 sxy = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ sx += wpf[i].mV[0];
+ sx2 += wpf[i].mV[0]*wpf[i].mV[0];
+ sy += wpf[i].mV[1];
+ sxy += wpf[i].mV[0]*wpf[i].mV[1];
+ }
+
+ bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
+ bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
+ }
+
+ {
+ // best fit line is y=bfm*x+bfb
+
+ //find point that is furthest to the right of line
+ F32 off_x = -1.f;
+ LLVector3 lp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ //y = bfm*x+bfb
+ //x = (y-bfb)/bfm
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+
+ lx = wpf[i].mV[0]-lx;
+
+ if (off_x < lx)
+ {
+ off_x = lx;
+ lp = wpf[i];
+ }
+ }
+
+ //get line with slope bfm through lp
+ // bfb = y-bfm*x
+ bfb = lp.mV[1]-bfm*lp.mV[0];
+
+ //calculate error
+ mShadowError.mV[j] = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+ mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
+ }
+
+ mShadowError.mV[j] /= wpf.size();
+ mShadowError.mV[j] /= size.mV[0];
+
+ if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff"))
+ { //just use ortho projection
+ mShadowFOV.mV[j] = -1.f;
+ origin.clearVec();
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //origin is where line x = 0;
+ origin.setVec(0,bfb,0);
+
+ F32 fovz = 1.f;
+ F32 fovx = 1.f;
+
+ LLVector3 zp;
+ LLVector3 xp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ if (fovz > -atz.mV[1])
+ {
+ zp = wpf[i];
+ fovz = -atz.mV[1];
+ }
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ if (fovx > -atx.mV[1])
+ {
+ fovx = -atx.mV[1];
+ xp = wpf[i];
+ }
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f);
+
+ mShadowFOV.mV[j] = fovx;
+
+ if (fovx < cutoff && fovz > cutoff)
+ {
+ //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
+ F32 d = zp.mV[2]/tan(cutoff);
+ F32 ny = zp.mV[1] + fabsf(d);
+
+ origin.mV[1] = ny;
+
+ fovz = 1.f;
+ fovx = 1.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ fovz = llmin(fovz, -atz.mV[1]);
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ fovx = llmin(fovx, -atx.mV[1]);
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
+ {
+ // llerrs << "WTF?" << llendl;
+ }
+
+ mShadowFOV.mV[j] = cutoff;
+ }
+
+
+ origin += center;
+
+ F32 ynear = -(max.mV[1]-origin.mV[1]);
+ F32 yfar = -(min.mV[1]-origin.mV[1]);
+
+ if (ynear < 0.1f) //keep a sensible near clip plane
+ {
+ F32 diff = 0.1f-ynear;
+ origin.mV[1] += diff;
+ ynear += diff;
+ yfar += diff;
+ }
+
+ if (fovx > cutoff)
+ { //just use ortho projection
+ origin.clearVec();
+ mShadowError.mV[j] = -1.f;
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //get perspective projection
+ view[j] = view[j].inverse();
+
+ glh::vec3f origin_agent(origin.mV);
+
+ //translate view to origin
+ view[j].mult_matrix_vec(origin_agent);
+
+ eye = LLVector3(origin_agent.v);
+
+ if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustOrigin[j] = eye;
+ }
+
+ view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
+
+ F32 fx = 1.f/tanf(fovx);
+ F32 fz = 1.f/tanf(fovz);
+
+ proj[j] = glh::matrix4f(-fx, 0, 0, 0,
+ 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
+ 0, 0, -fz, 0,
+ 0, -1.f, 0, 0);
+ }
+ }
+ }
+
+ //shadow_cam.setFar(128.f);
+ shadow_cam.setOriginAndLookAt(eye, up, center);
+
+ shadow_cam.setOrigin(0,0,0);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+ shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = mShadowModelview[j].m[i];
+ gGLLastProjection[i] = mShadowProjection[j].m[i];
+ }
+
+ mShadowModelview[j] = view[j];
+ mShadowProjection[j] = proj[j];
+
+
+ mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
+
+ stop_glerror();
+
+ mShadow[j].bindTarget();
+ mShadow[j].getViewport(gGLViewport);
+ mShadow[j].clear();
+
+ {
+ static LLCullResult result[4];
+
+ //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+ renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
+ }
+
+ mShadow[j].flush();
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+ mShadowCamera[j+4] = shadow_cam;
+ }
+ }
+
+
+ //hack to disable projector shadows
+ bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
+
+ if (gen_shadow)
+ {
+ F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
+
+ //update shadow targets
+ for (U32 i = 0; i < 2; i++)
+ { //for each current shadow
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+
+ if (mShadowSpotLight[i].notNull() &&
+ (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+ mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+ { //keep this spotlight
+ mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+ }
+ else
+ { //fade out this light
+ mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+
+ if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+ { //faded out, grab one of the pending spots (whichever one isn't already taken)
+ if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+ }
+ else
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+ }
+ }
+ }
+ }
+
+ for (S32 i = 0; i < 2; i++)
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ if (mShadowSpotLight[i].isNull())
+ {
+ continue;
+ }
+
+ LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+
+ if (!volume)
+ {
+ mShadowSpotLight[i] = NULL;
+ continue;
+ }
+
+ LLDrawable* drawable = mShadowSpotLight[i];
+
+ LLVector3 params = volume->getSpotLightParams();
+ F32 fov = params.mV[0];
+
+ //get agent->light space matrix (modelview)
+ LLVector3 center = drawable->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+
+ //get near clip plane
+ LLVector3 scale = volume->getScale();
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = center+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+
+ view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+
+ view[i+4] = view[i+4].inverse();
+
+ //get perspective matrix
+ F32 near_clip = dist+0.01f;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = dist+volume->getLightRadius()*1.5f;
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[i+4]);
+ glh_set_current_projection(proj[i+4]);
+
+ mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
+
+ for (U32 j = 0; j < 16; j++)
+ {
+ gGLLastModelView[j] = mShadowModelview[i+4].m[j];
+ gGLLastProjection[j] = mShadowProjection[i+4].m[j];
+ }
+
+ mShadowModelview[i+4] = view[i+4];
+ mShadowProjection[i+4] = proj[i+4];
+
+ LLCamera shadow_cam = camera;
+ shadow_cam.setFar(far_clip);
+ shadow_cam.setOrigin(origin);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ stop_glerror();
+
+ mShadow[i+4].bindTarget();
+ mShadow[i+4].getViewport(gGLViewport);
+ mShadow[i+4].clear();
+
+ static LLCullResult result[2];
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+
+ renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+
+ mShadow[i+4].flush();
+ }
+ }
+
+ if (!gSavedSettings.getBOOL("CameraOffset"))
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+ }
+ else
+ {
+ glh_set_current_modelview(view[1]);
+ glh_set_current_projection(proj[1]);
+ glLoadMatrixf(view[1].m);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(proj[1].m);
+ glMatrixMode(GL_MODELVIEW);
+ }
+ gGL.setColorMask(true, false);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = last_modelview[i];
+ gGLLastProjection[i] = last_projection[i];
+ }
+
+ popRenderTypeMask();
+}
+
+void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
+{
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!group->isDead() &&
+ (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
+ gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
+ group->mDrawMap.find(type) != group->mDrawMap.end())
+ {
+ pass->renderGroup(group,type,mask,texture);
+ }
+ }
+}
+
+void LLPipeline::generateImpostor(LLVOAvatar* avatar)
+{
+ LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ static LLCullResult result;
+ result.clear();
+ grabReferences(result);
+
+ if (!avatar || !avatar->mDrawable)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
+
+ pushRenderTypeMask();
+
+ if (muted)
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ }
+ else
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ END_RENDER_TYPES);
+ }
+
+ S32 occlusion = sUseOcclusion;
+ sUseOcclusion = 0;
+ sReflectionRender = sRenderDeferred ? FALSE : TRUE;
+ sShadowRender = TRUE;
+ sImpostorRender = TRUE;
+
+ LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
+ markVisible(avatar->mDrawable, *viewer_camera);
+ LLVOAvatar::sUseImpostors = FALSE;
+
+ LLVOAvatar::attachment_map_t::iterator iter;
+ for (iter = avatar->mAttachmentPoints.begin();
+ iter != avatar->mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject* attached_object = (*attachment_iter))
+ {
+ markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+ }
+ }
+ }
+
+ stateSort(*LLViewerCamera::getInstance(), result);
+
+ const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
+ LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
+
+ LLCamera camera = *viewer_camera;
+
+ camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
+
+ LLVector2 tdim;
+
+
+ LLVector4a half_height;
+ half_height.setSub(ext[1], ext[0]);
+ half_height.mul(0.5f);
+
+ LLVector4a left;
+ left.load3(camera.getLeftAxis().mV);
+ left.mul(left);
+ left.normalize3fast();
+
+ LLVector4a up;
+ up.load3(camera.getUpAxis().mV);
+ up.mul(up);
+ up.normalize3fast();
+
+ tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
+ tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+
+ F32 distance = (pos-camera.getOrigin()).length();
+ F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
+ F32 aspect = tdim.mV[0]/tdim.mV[1];
+ glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
+ glh_set_current_projection(persp);
+ glLoadMatrixf(persp.m);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glh::matrix4f mat;
+ camera.getOpenGLTransform(mat.m);
+
+ mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
+
+ glLoadMatrixf(mat.m);
+ glh_set_current_modelview(mat);
+
+ glClearColor(0.0f,0.0f,0.0f,0.0f);
+ gGL.setColorMask(true, true);
+
+ // get the number of pixels per angle
+ F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
+
+ //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
+ U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
+ U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
+
+ if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
+ resY != avatar->mImpostor.getHeight())
+ {
+ avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ addDeferredAttachments(avatar->mImpostor);
+ }
+
+ gGL.getTexUnit(0)->bind(&avatar->mImpostor);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ avatar->mImpostor.bindTarget();
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ avatar->mImpostor.clear();
+ renderGeomDeferred(camera);
+ renderGeomPostDeferred(camera);
+ }
+ else
+ {
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, resX, resY);
+ avatar->mImpostor.clear();
+ renderGeom(camera);
+ }
+
+ { //create alpha mask based on depth buffer (grey out if muted)
+ if (LLPipeline::sRenderDeferred)
+ {
+ GLuint buff = GL_COLOR_ATTACHMENT0;
+ glDrawBuffersARB(1, &buff);
+ }
+
+ LLGLDisable blend(GL_BLEND);
+
+ if (muted)
+ {
+ gGL.setColorMask(true, true);
+ }
+ else
+ {
+ gGL.setColorMask(false, true);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ gGL.flush();
+
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ static const F32 clip_plane = 0.99999f;
+
+ gGL.color4ub(64,64,64,255);
+ gGL.begin(LLRender::QUADS);
+ gGL.vertex3f(-1, -1, clip_plane);
+ gGL.vertex3f(1, -1, clip_plane);
+ gGL.vertex3f(1, 1, clip_plane);
+ gGL.vertex3f(-1, 1, clip_plane);
+ gGL.end();
+ gGL.flush();
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
+ avatar->mImpostor.flush();
+
+ avatar->setImpostorDim(tdim);
+
+ LLVOAvatar::sUseImpostors = TRUE;
+ sUseOcclusion = occlusion;
+ sReflectionRender = FALSE;
+ sImpostorRender = FALSE;
+ sShadowRender = FALSE;
+ popRenderTypeMask();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ avatar->mNeedsImpostorUpdate = FALSE;
+ avatar->cacheImpostorValues();
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+}
+
+BOOL LLPipeline::hasRenderBatches(const U32 type) const
+{
+ return sCull->getRenderMapSize(type) > 0;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
+{
+ return sCull->beginRenderMap(type);
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
+{
+ return sCull->endRenderMap(type);
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
+{
+ return sCull->beginAlphaGroups();
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
+{
+ return sCull->endAlphaGroups();
+}
+
+BOOL LLPipeline::hasRenderType(const U32 type) const
+{
+ // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
+ // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
+ // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
+ return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
+}
+
+void LLPipeline::setRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = TRUE;
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ return TRUE;
+ }
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ return FALSE;
+}
+
+void LLPipeline::pushRenderTypeMask()
+{
+ std::string cur_mask;
+ cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.push(cur_mask);
+}
+
+void LLPipeline::popRenderTypeMask()
+{
+ if (mRenderTypeEnableStack.empty())
+ {
+ llerrs << "Depleted render type stack." << llendl;
+ }
+
+ memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.pop();
+}
+
+void LLPipeline::andRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ BOOL tmp[NUM_RENDER_TYPES];
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ tmp[i] = FALSE;
+ }
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ tmp[type] = TRUE;
+ }
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = tmp[i];
+ }
+
+}
+
+void LLPipeline::clearRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = FALSE;
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 7d767b9222..731bd74547 100644
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -115,9 +115,6 @@
name="AlertCautionTextColor"
reference="LtYellow" />
<color
- name="AlertTextColor"
- value="0.58 0.66 0.84 1" />
- <color
name="AvatarListItemIconDefaultColor"
reference="White" />
<color
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_chat.xml b/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
index 3705a5902a..ed499619f6 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="IM chats" name="EnableIMChatPopups" tool_tip="Vælg for at se popup vindue når personlige beskeder (IM) modtages"/>
<spinner label="Tid før chatvisning forsvinder:" name="nearby_toasts_lifetime"/>
<spinner label="Tid før chatvisning forsvinder:" name="nearby_toasts_fadingtime"/>
- <check_box label="Benyt maskin-oversættelse ved chat (håndteret af Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Benyt maskin-oversættelse ved chat (håndteret af Google)</text>
<text name="translate_language_text" width="110">
Oversæt chat til :
</text>
diff --git a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
index 5810cc21e7..067463be02 100644
--- a/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/da/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Midterste museknap
</panel.string>
<slider label="Generel" name="System Volume"/>
- <check_box initial_value="true" label="Sluk lyd når minimeret" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Sluk lyd når minimeret</text>
<slider label="Knapper" name="UI Volume"/>
<slider label="Omgivelser" name="Wind Volume"/>
<slider label="Lyd effekter" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
index 8086128dd7..8c8cdd31fe 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="IM-Chats" name="EnableIMChatPopups" tool_tip="Markieren, um Popups zu sehen, wenn Instant Message eintrifft"/>
<spinner label="Lebenszeit von Toasts für Chat in der Nähe:" name="nearby_toasts_lifetime"/>
<spinner label="Ein-/Ausblenddauer von Toasts für Chat in der Nähe:" name="nearby_toasts_fadingtime"/>
- <check_box label="Bei Chat Maschinenübersetzung verwenden (Service von Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Bei Chat Maschinenübersetzung verwenden (Service von Google)</text>
<text name="translate_language_text">
Chat übersetzen in:
</text>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_sound.xml b/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
index 0f029d8664..07631b6a91 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Mittlere Maustaste
</panel.string>
<slider label="Master-Lautstärke" name="System Volume"/>
- <check_box initial_value="true" label="Stummschalten, wenn minimiert" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Stummschalten, wenn minimiert</text>
<slider label="Schaltflächen" name="UI Volume"/>
<slider label="Umgebung" name="Wind Volume"/>
<slider label="Soundeffekte" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml
index 8eee8f44b5..dcfa8bc060 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences.xml
@@ -45,7 +45,7 @@
name="pref core"
tab_group="1"
tab_position="left"
- tab_width="115"
+ tab_width="140"
tab_padding_right="0"
top="21"
width="658">
@@ -96,7 +96,7 @@
filename="panel_preferences_colors.xml"
label="Colors"
layout="topleft"
- help_topic="preferences_im_tab"
+ help_topic="preferences_colors_tab"
name="colors" />
<panel
class="panel_preference"
diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
new file mode 100644
index 0000000000..c39c26f25f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ name="media ctrl context menu">
+ <menu_item_call
+ label="Cut"
+ layout="topleft"
+ name="Cut">
+ <menu_item_call.on_click
+ function="Edit.Cut" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCut" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy"
+ layout="topleft"
+ name="Copy">
+ <menu_item_call.on_click
+ function="Edit.Copy" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCopy" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste"
+ layout="topleft"
+ name="Paste">
+ <menu_item_call.on_click
+ function="Edit.Paste" />
+ <menu_item_call.on_enable
+ function="Edit.EnablePaste" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_text_editor.xml b/indra/newview/skins/default/xui/en/menu_text_editor.xml
index ecd96088e7..fe8489166b 100644
--- a/indra/newview/skins/default/xui/en/menu_text_editor.xml
+++ b/indra/newview/skins/default/xui/en/menu_text_editor.xml
@@ -4,8 +4,7 @@
<menu_item_call
label="Cut"
layout="topleft"
- name="Cut"
- shortcut="control|X">
+ name="Cut">
<menu_item_call.on_click
function="Edit.Cut" />
<menu_item_call.on_enable
@@ -14,8 +13,7 @@
<menu_item_call
label="Copy"
layout="topleft"
- name="Copy"
- shortcut="control|C">
+ name="Copy">
<menu_item_call.on_click
function="Edit.Copy" />
<menu_item_call.on_enable
@@ -24,8 +22,7 @@
<menu_item_call
label="Paste"
layout="topleft"
- name="Paste"
- shortcut="control|V">
+ name="Paste">
<menu_item_call.on_click
function="Edit.Paste" />
<menu_item_call.on_enable
@@ -34,8 +31,7 @@
<menu_item_call
label="Delete"
layout="topleft"
- name="Delete"
- shortcut="Del">
+ name="Delete">
<menu_item_call.on_click
function="Edit.Delete" />
<menu_item_call.on_enable
@@ -44,8 +40,7 @@
<menu_item_call
label="Select All"
layout="topleft"
- name="Select All"
- shortcut="control|A">
+ name="Select All">
<menu_item_call.on_click
function="Edit.SelectAll" />
<menu_item_call.on_enable
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 5b144cafdf..ed7de6a19f 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7040,22 +7040,27 @@ Hiding the Speak button will disable the voice feature.
</notification>
<notification
- name="HintDisplayName"
- label="Display Name"
+ name="HintMoveClick"
+ label=""
type="hint"
unique="true">
- Set your customizable display name here. This is in addition to your unique username, which can't be changed. You can change how you see other people's names in your preferences.
+1. Click to Walk
+Click anywhere on the ground to walk to that spot.
+
+2. Click and Drag to Rotate View
+Click and drag anywhere on the world to rotate your view
+ <tag>custom_skin</tag>
</notification>
<notification
- name="HintMoveArrows"
- label="Move"
+ name="HintDisplayName"
+ label="Display Name"
type="hint"
unique="true">
- To walk, use the directional keys on your keyboard. You can run by pressing the Up arrow twice.
- <tag>custom_skin</tag>
+ Set your customizable display name here. This is in addition to your unique username, which can't be changed. You can change how you see other people's names in your preferences.
</notification>
+
<notification
name="HintView"
label="View"
diff --git a/indra/newview/skins/default/xui/en/panel_hint.xml b/indra/newview/skins/default/xui/en/panel_hint.xml
index e2e9d0aef0..f7434f0330 100644
--- a/indra/newview/skins/default/xui/en/panel_hint.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
width="205"
- height="100">
+ height="34">
<text name="hint_title"
font="SansSerifMedium"
left="8"
@@ -15,8 +15,8 @@
left="8"
right="197"
top="26"
- bottom="92"
- follows="all"
+ bottom="26"
+ follows="left|right|bottom"
text_color="Black"
wrap="true"/>
<button right="197"
diff --git a/indra/newview/skins/default/xui/en/panel_hint_image.xml b/indra/newview/skins/default/xui/en/panel_hint_image.xml
index 00b6e42497..df05d50dc5 100644
--- a/indra/newview/skins/default/xui/en/panel_hint_image.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint_image.xml
@@ -1,33 +1,43 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
- width="205"
- height="140"
+ width="305"
+ height="40"
layout="topleft">
<text name="hint_title"
font="SansSerifMedium"
left="8"
- right="180"
+ right="290"
top="8"
bottom="20"
follows="left|right|top"
text_color="Black"
wrap="false"/>
- <icon name="hint_image"
- left="42"
- top="25"
- width="115"
- height="86"
- image_name="arrow_keys.png"
- />
+ <layout_stack left="0"
+ top="25"
+ width="305"
+ height="0"
+ follows="left|top|right"
+ orientation="horizontal">
+ <layout_panel auto_resize="true" width="100"/>
+ <layout_panel auto_resize="true" width="0">
+ <icon name="hint_image"
+ top="0"
+ left="0"
+ height="0"
+ width="0"
+ follows="all"/>
+ </layout_panel>
+ <layout_panel auto_resize="true" width="100"/>
+ </layout_stack>
<text name="hint_text"
left="8"
- right="197"
- top_pad="5"
- bottom="120"
- follows="all"
+ right="297"
+ top="30"
+ bottom="30"
+ follows="left|right|bottom"
text_color="Black"
wrap="true"/>
- <button right="197"
+ <button right="297"
top="8"
width="16"
height="16"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 4c2faddfe4..8d0f1437e6 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -133,7 +133,6 @@ label="Remember password"
max_chars="128"
tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
top_pad="0"
- control_name="SessionSettingsFile"
name="mode_combo"
width="110">
<combo_box.item
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml
index 559df5bec9..714dca7fac 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_alerts.xml
@@ -67,7 +67,7 @@
image_overlay="Arrow_Up"
hover_glow_amount="0.15"
layout="topleft"
- left="180"
+ left="200"
name="enable_this_popup"
top_pad="5"
width="40">
@@ -81,7 +81,7 @@
image_overlay="Arrow_Down"
hover_glow_amount="0.15"
layout="topleft"
- left_pad="40"
+ left_pad="20"
name="disable_this_popup"
top_delta="0"
width="40">
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
index a1082d9c32..404537e1f2 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
@@ -208,15 +208,27 @@
<check_box
control_name="TranslateChat"
enabled="true"
- height="16"
- label="Use machine translation while chatting (powered by Google)"
+ height="16"
layout="topleft"
left="30"
name="translate_chat_checkbox"
- bottom_delta="30"
+ top_pad="5"
width="400" />
+ <!-- *HACK
+ After storm-1109 will be fixed: instead of using this text_box, word_wrap should be applied for "translate_chat_checkbox" check_box's label.-->
+ <text
+ follows="top|left"
+ height="15"
+ layout="topleft"
+ left="50"
+ name="translate_chb_label"
+ top_delta="1"
+ width="450"
+ wrap="true">
+ Use machine translation while chatting (powered by Google)
+ </text>
<text
- bottom_delta="30"
+ top_pad="20"
name="translate_language_text"
follows="left|top"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_general.xml b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
index 36f8f99178..9c718fdb87 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_general.xml
@@ -307,17 +307,6 @@
tool_tip="Check to use display names in chat, IM, name tags, etc."
top_pad="3"/>
- <check_box
- control_name="EnableUIHints"
- follows="top|left"
- height="16"
- label="Enable Viewer UI Hints"
- layout="topleft"
- left="27"
- name="viewer_hints_check"
- top_pad="5"
- width="237"/>
-
<text
type="string"
length="1"
@@ -326,7 +315,7 @@
layout="topleft"
left="30"
name="inworld_typing_rg_label"
- top_pad="6"
+ top_pad="1"
width="400">
Pressing letter keys:
</text>
@@ -348,9 +337,9 @@
width="150" />
<radio_item
label="Affects movement (i.e. WASD)"
- left_pad="0"
+ left="0"
layout="topleft"
- top_delta="0"
+ top="18"
height="16"
name="radio_move"
value="0"
@@ -365,7 +354,7 @@
layout="topleft"
left="30"
name="title_afk_text"
- top_pad="4"
+ top_pad="15"
width="190">
Away timeout:
</text>
@@ -408,7 +397,7 @@
left="30"
mouse_opaque="false"
name="text_box3"
- top_pad="5"
+ top_pad="3"
width="240">
Busy mode response:
</text>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_move.xml b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
index d2fc6ea09a..04412bdb9c 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_move.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_move.xml
@@ -120,12 +120,13 @@
type="string"
length="1"
follows="left|top"
- height="10"
+ height="15"
layout="topleft"
left_delta="3"
name=" Mouse Sensitivity"
top_pad="10"
- width="160">
+ width="160"
+ wrap="true">
Mouselook mouse sensitivity:
</text>
<slider
@@ -139,7 +140,7 @@
max_val="15"
name="mouse_sensitivity"
top_delta="-1"
- width="145" />
+ width="115" />
<check_box
control_name="InvertMouse"
height="16"
@@ -158,7 +159,7 @@
left="78"
name="arrow_keys_move_avatar_check"
width="237"
- top_pad="1"/>
+ top_pad="10"/>
<check_box
control_name="AllowTapTapHoldRun"
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index ef25588ca3..30be5bc853 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -42,7 +42,7 @@
</text>
<check_box
height="16"
- enabled="true"
+ enabled="false"
label="Show me in Search results"
layout="topleft"
left="30"
@@ -82,8 +82,8 @@
control_name="ShowFavoritesOnLogin"
enabled="false"
height="16"
- label="Show my Favorite Landmarks at Login (via &apos;Start At&apos; drop-down menu)"
layout="topleft"
+ label="Show my Favorite Landmarks at Login (via &apos;Start At&apos; drop-down menu)"
left="30"
name="favorites_on_login_check"
top_pad="10"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 26af8dc29d..f89494da72 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -50,12 +50,24 @@
control_name="MuteWhenMinimized"
height="15"
initial_value="true"
- label="Mute when minimized"
layout="topleft"
name="mute_when_minimized"
top_delta="3"
left_pad="5"
- width="235" />
+ width="20" />
+ <!-- *HACK
+ After storm-1109 will be fixed: instead of using this text_box, word_wrap should be applied for "mute_when_minimized" check_box's label.-->
+ <text
+ follows="top|left"
+ height="15"
+ layout="topleft"
+ left_pad="0"
+ name="mute_chb_label"
+ top_delta="0"
+ width="150"
+ wrap="true">
+ Mute when minimized
+ </text>
<slider
control_name="AudioLevelUI"
disabled_control="MuteAudio"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index d36220385d..cb701e03da 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -453,23 +453,6 @@
</layout_panel>
</layout_stack>
</layout_panel>
- <layout_panel
- follows="bottom|left"
- height="30"
- layout="topleft"
- name="profile_me_buttons_panel"
- visible="false"
- width="313">
- <button
- follows="bottom|right"
- height="23"
- left="20"
- top="0"
- label="Edit Profile"
- name="edit_profile_btn"
- tool_tip="Edit your personal information"
- width="130" />
- </layout_panel>
</layout_stack>
</panel>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
index 0b304fe287..aba85f9ff1 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="Chats de MI" name="EnableIMChatPopups" tool_tip="Activa esta casilla para ver una ventana emergente cada vez que recibas un mensaje instantáneo"/>
<spinner label="Duración de los interlocutores favoritos:" name="nearby_toasts_lifetime"/>
<spinner label="Tiempo de los otros interlocutores:" name="nearby_toasts_fadingtime"/>
- <check_box label="Usar la traducción automática (con Google) en el chat" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Usar la traducción automática (con Google) en el chat</text>
<text name="translate_language_text">
Traducir el chat al:
</text>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_sound.xml b/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
index db3659abcd..2bc82307a8 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Botón medio del ratón
</panel.string>
<slider label="Volumen general" name="System Volume"/>
- <check_box initial_value="true" label="Silenciar cuando minimice" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Silenciar cuando minimice</text>
<slider label="Botones" name="UI Volume"/>
<slider label="Ambiental" name="Wind Volume"/>
<slider label="Efectos de sonido" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
index 4b3fc35150..d5cecfc698 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="Chats IM" name="EnableIMChatPopups" tool_tip="Cocher cette case pour qu&apos;un popup s&apos;affiche à réception d&apos;un message instantané."/>
<spinner label="Durée de vie du popup Chat près de moi :" name="nearby_toasts_lifetime"/>
<spinner label="Disparition progressive du popup Chat près de moi :" name="nearby_toasts_fadingtime"/>
- <check_box label="Utiliser la traduction automatique lors des chats (fournie par Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Utiliser la traduction automatique lors des chats (fournie par Google)</text>
<text name="translate_language_text">
Traduire le chat en :
</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml b/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
index 48630918d7..ac7f72d367 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Bouton central de la souris
</panel.string>
<slider label="Volume principal" name="System Volume"/>
- <check_box initial_value="true" label="Couper quand minimisé" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Couper quand minimisé</text>
<slider label="Boutons" name="UI Volume"/>
<slider label="Ambiant" name="Wind Volume"/>
<slider label="Effets sonores" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_chat.xml b/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
index 4a1bbdf64a..208dd5ed28 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_chat.xml
@@ -56,7 +56,8 @@
<radio_item label="Finestre separate" name="radio" value="0"/>
<radio_item label="Schede" name="radio2" value="1"/>
</radio_group>
- <check_box label="Usa la traduzione meccanica durante le chat (tecnologia Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Usa la traduzione meccanica durante le chat (tecnologia Google)</text>
<text name="translate_language_text" width="110">
Traduci chat in:
</text>
diff --git a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
index 6e70a314c5..e2332b63d0 100644
--- a/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/it/panel_preferences_sound.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Suoni" name="Preference Media panel">
<slider label="Vol. principale" name="System Volume"/>
- <check_box initial_value="true" label="Disatt. se a icona" name="mute_when_minimized"/>
+ <check_box initial_value="true" label="" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Disatt. se a icona</text>
<slider label="Pulsanti" name="UI Volume"/>
<slider label="Ambiente" name="Wind Volume"/>
<slider label="Effetti sonori" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml b/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
index c260cebef8..ce2a0f35e4 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_chat.xml
@@ -56,7 +56,8 @@
<radio_item label="別々のウィンドウ" name="radio" value="0"/>
<radio_item label="タブ" name="radio2" value="1"/>
</radio_group>
- <check_box label="チャット中に内容を機械翻訳する(Google翻訳)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >チャット中に内容を機械翻訳する(Google翻訳)</text>
<text name="translate_language_text">
翻訳する言語:
</text>
diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_sound.xml b/indra/newview/skins/default/xui/ja/panel_preferences_sound.xml
index 9fbbd46220..74696a3b35 100644
--- a/indra/newview/skins/default/xui/ja/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/ja/panel_preferences_sound.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="サウンド" name="Preference Media panel">
<slider label="全体の音量" name="System Volume"/>
- <check_box initial_value="true" label="最小化でミュート" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">最小化でミュート</text>
<slider label="ボタン" name="UI Volume"/>
<slider label="風" name="Wind Volume"/>
<slider label="効果音" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/nl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/nl/panel_preferences_sound.xml
index 2b709bde40..5ded015868 100644
--- a/indra/newview/skins/default/xui/nl/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/nl/panel_preferences_sound.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<panel label="Geluid" name="Preference Media panel">
<slider label="Hoofd volume" name="System Volume"/>
- <check_box initial_value="true" label="Dempen indien geminimaliseerd" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Dempen indien geminimaliseerd</text>
<slider label="Omliggend" name="Wind Volume"/>
<slider label="Knoppen" name="UI Volume"/>
<slider label="Media" name="Media Volume"/>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
index c7142c8419..4a4e6509ab 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="Czat IM" name="EnableIMChatPopups" tool_tip="Zaznacz aby widzieć wyskakujące okienka kiedy IM się pojawia"/>
<spinner label="Czas widoczności czatu w pobliżu:" name="nearby_toasts_lifetime"/>
<spinner label="Czas znikania czatu w pobliżu:" name="nearby_toasts_fadingtime"/>
- <check_box label="Używaj translatora podczas rozmowy (wspierany przez Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Używaj translatora podczas rozmowy (wspierany przez Google)</text>
<text name="translate_language_text">
Przetłumacz czat na:
</text>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
index ac93949a1b..692f24715b 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Środkowy przycisk myszy
</panel.string>
<slider label="Główny" name="System Volume"/>
- <check_box initial_value="true" label="Wycisz podczas minimalizacji" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Wycisz podczas minimalizacji</text>
<slider label="Interfejs" name="UI Volume"/>
<slider label="Otoczenie" name="Wind Volume"/>
<slider label="Efekty dźwiękowe" name="SFX Volume"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml b/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
index 368c474ee9..412bdbb13e 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_chat.xml
@@ -29,7 +29,8 @@
<check_box label="Bate-papos de MI" name="EnableIMChatPopups" tool_tip="Exibir pop-up de mensagens instantâneas novas"/>
<spinner label="Transição de avisos de bate-papos por perto:" name="nearby_toasts_lifetime"/>
<spinner label="Transição de avisos de bate-papos por perto:" name="nearby_toasts_fadingtime"/>
- <check_box label="Traduzir bate-papo automaticamente (via Google)" name="translate_chat_checkbox"/>
+ <check_box name="translate_chat_checkbox"/>
+ <text name="translate_chb_label" >Traduzir bate-papo automaticamente (via Google)</text>
<text name="translate_language_text">
Traduzir bate-papo para:
</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
index 3846bfb377..6053deb5b1 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_sound.xml
@@ -4,7 +4,8 @@
Botão do meio do mouse
</panel.string>
<slider label="Volume principal" name="System Volume"/>
- <check_box initial_value="true" label="Silenciar ao minimizar" name="mute_when_minimized"/>
+ <check_box initial_value="true" name="mute_when_minimized"/>
+ <text name="mute_chb_label">Silenciar ao minimizar</text>
<slider label="Botões" name="UI Volume"/>
<slider label="Ambiente" name="Wind Volume"/>
<slider label="Efeitos sonoros" name="SFX Volume"/>
diff --git a/indra/newview/skins/minimal/textures/click_to_move.png b/indra/newview/skins/minimal/textures/click_to_move.png
new file mode 100644
index 0000000000..74e3faa8ff
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/click_to_move.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/textures.xml b/indra/newview/skins/minimal/textures/textures.xml
index 3e2f5cd397..b4848a0619 100644
--- a/indra/newview/skins/minimal/textures/textures.xml
+++ b/indra/newview/skins/minimal/textures/textures.xml
@@ -2,6 +2,7 @@
<textures version="101">
<texture name="Button_Separator" file_name="bottomtray/button_separator.png" preload="true" />
<texture name="arrow_keys.png"/>
+ <texture name="click_to_move" file_name="click_to_move.png"/>
<texture name="bottomtray_close_off" file_name="bottomtray/close_off.png" preload="true" />
<texture name="bottomtray_close_over" file_name="bottomtray/close_over.png" preload="true" />
<texture name="bottomtray_close_press" file_name="bottomtray/close_press.png" preload="true" />
diff --git a/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_favorites.xml b/indra/newview/skins/minimal/xui/en/menu_favorites.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_favorites.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_favorites.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_group_plus.xml b/indra/newview/skins/minimal/xui/en/menu_group_plus.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_group_plus.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_group_plus.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inventory.xml b/indra/newview/skins/minimal/xui/en/menu_inventory.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_inventory.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_inventory.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_mini_map.xml b/indra/newview/skins/minimal/xui/en/menu_mini_map.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_mini_map.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_mini_map.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_navbar.xml b/indra/newview/skins/minimal/xui/en/menu_navbar.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_navbar.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_navbar.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_object_icon.xml b/indra/newview/skins/minimal/xui/en/menu_object_icon.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_object_icon.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_object_icon.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_groups.xml b/indra/newview/skins/minimal/xui/en/menu_people_groups.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_people_groups.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_people_groups.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_slurl.xml b/indra/newview/skins/minimal/xui/en/menu_slurl.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_slurl.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_slurl.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml
index 9ebab9ef98..d3d9e2ef8a 100644
--- a/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml
+++ b/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu/>
+<menu visible="false"/>
diff --git a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
index 0145de8be9..d0a77e8c2a 100644
--- a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
@@ -163,7 +163,7 @@
layout="topleft"
left="0"
name="destination_btn"
- tool_tip="Shows people window"
+ tool_tip="Shows destinations"
top="5"
is_toggle="true"
use_ellipses="true"
diff --git a/indra/newview/skins/minimal/xui/en/panel_login.xml b/indra/newview/skins/minimal/xui/en/panel_login.xml
index ef058e5567..3903658e71 100644
--- a/indra/newview/skins/minimal/xui/en/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_login.xml
@@ -134,7 +134,6 @@ top="20"
max_chars="128"
top_pad="0"
tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
- control_name="SessionSettingsFile"
name="mode_combo"
width="120">
<combo_box.item
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index e9d4d99753..7164934b26 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -4,7 +4,7 @@
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2011, 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
@@ -2233,7 +2233,13 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
case MEDIA_EVENT_LINK_HOVERED:
{
std::cerr << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << std::endl;
- };
+ }
+ break;
+
+ default:
+ {
+ std::cerr << "Media event: <unknown>, code is: " << int(event) << std::endl;
+ }
break;
}
}