summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags13
-rw-r--r--[-rwxr-xr-x]BuildParams13
-rw-r--r--[-rwxr-xr-x]autobuild.xml0
-rwxr-xr-x[-rw-r--r--]build.sh0
-rw-r--r--doc/contributions.txt1783
-rw-r--r--[-rwxr-xr-x]indra/cmake/Copy3rdPartyLibs.cmake0
-rwxr-xr-x[-rw-r--r--]indra/cmake/FMOD.cmake0
-rw-r--r--[-rwxr-xr-x]indra/cmake/LLPrimitive.cmake0
-rw-r--r--[-rwxr-xr-x]indra/cmake/LLTestCommand.cmake0
-rw-r--r--[-rwxr-xr-x]indra/cmake/Python.cmake0
-rwxr-xr-x[-rw-r--r--]indra/cmake/run_build_test.py0
-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--[-rwxr-xr-x]indra/llcommon/llfasttimer.h0
-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--[-rwxr-xr-x]indra/llprimitive/llmodel.cpp0
-rw-r--r--[-rwxr-xr-x]indra/llprimitive/llmodel.h0
-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--[-rwxr-xr-x]indra/llvfs/lldir_win32.h0
-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
-rw-r--r--[-rwxr-xr-x]indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/CA.pem6471
-rw-r--r--[-rwxr-xr-x]indra/newview/app_settings/settings.xml26237
-rw-r--r--indra/newview/app_settings/settings_minimal.xml6
-rw-r--r--indra/newview/character/avatar_lad.xml20
-rw-r--r--[-rwxr-xr-x]indra/newview/installers/windows/installer_template.nsi0
-rw-r--r--[-rwxr-xr-x]indra/newview/installers/windows/lang_en-us.nsibin7542 -> 7542 bytes
-rw-r--r--[-rwxr-xr-x]indra/newview/llagent.cpp11
-rw-r--r--indra/newview/llagentcamera.cpp29
-rw-r--r--indra/newview/llagentlistener.cpp40
-rw-r--r--indra/newview/llagentlistener.h2
-rw-r--r--[-rwxr-xr-x]indra/newview/llagentpilot.cpp0
-rw-r--r--[-rwxr-xr-x]indra/newview/llagentpilot.h0
-rw-r--r--[-rwxr-xr-x]indra/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--[-rwxr-xr-x]indra/newview/llfasttimerview.cpp0
-rw-r--r--indra/newview/llfirstuse.cpp6
-rw-r--r--indra/newview/llfloaterbump.cpp2
-rw-r--r--indra/newview/llfloaterhelpbrowser.cpp1
-rw-r--r--[-rwxr-xr-x]indra/newview/llfloatermodelpreview.cpp0
-rw-r--r--[-rwxr-xr-x]indra/newview/llfloatermodelpreview.h0
-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--[-rwxr-xr-x]indra/newview/llmeshrepository.cpp0
-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
-rw-r--r--[-rwxr-xr-x]indra/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
-rw-r--r--[-rwxr-xr-x]indra/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
-rw-r--r--[-rwxr-xr-x]indra/newview/llviewerstats.h0
-rw-r--r--[-rwxr-xr-x]indra/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
-rw-r--r--[-rwxr-xr-x]indra/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--[-rwxr-xr-x]indra/newview/skins/default/xui/en/floater_model_preview.xml0
-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
-rw-r--r--install.xml1898
212 files changed, 45496 insertions, 40567 deletions
diff --git a/.hgtags b/.hgtags
index 4bb008fc0b..d104ee3124 100644
--- a/.hgtags
+++ b/.hgtags
@@ -54,6 +54,7 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b
0000000000000000000000000000000000000000 76f586a8e22b
54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
+b542f8134a2bb5dd054ff4e509a44b2ee463b1bf nat-eventapi2-base
7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
@@ -72,6 +73,7 @@ b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-34_2.5.0-beta3
b723921b5c711bd24dbe77dc76ef488b544dac78 2.5.0-release
b723921b5c711bd24dbe77dc76ef488b544dac78 DRTVWR-31_2.5.0-release
92e58e51776a4f8c29069b1a62ff21454d2085f0 2.6.0-start
+3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work
63a6aedfce785a6c760377bf685b2dae616797d2 2.5.1-start
4dede9ae1ec74d41f6887719f6f1de7340d8578d 2.5.1-release
4dede9ae1ec74d41f6887719f6f1de7340d8578d DRTVWR-37_2.5.1-release
@@ -88,12 +90,19 @@ f1827b441e05bf37c68e2c15ebc6d09e9b03f527 2.6.0-start
c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start
c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1
c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1
-9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2
-9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2
+c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release
+c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release
56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start
42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release
42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release
d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1
d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1
+214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release
+214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release
52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py
ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start
+d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1
+d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1
+74cd32a06837b0c2cb793b2e8d4d82f5d49462b2 2.6.4-start
+74cd32a06837b0c2cb793b2e8d4d82f5d49462b2 2.6.4-start
+f632f87bb71b0f13d21f2f64b0c42cedb008c749 2.6.4-start
diff --git a/BuildParams b/BuildParams
index 7a2c2c9fb6..14bb2c1765 100755..100644
--- a/BuildParams
+++ b/BuildParams
@@ -69,7 +69,8 @@ viewer-pre-release.viewer_channel = "Second Life Release"
viewer-pre-release.login_channel = "Second Life Release"
viewer-pre-release.build_debug_release_separately = true
viewer-pre-release.build_viewer_update_version_manager = true
-viewer-pre-release.release-viewer.jira = DRTVWR-39
+#viewer-pre-release.release-viewer.jira = DRTVWR-13
+
# =======================================
# brad
# ========================================
@@ -184,12 +185,10 @@ media.build_viewer_update_version_manager = false
# oz
# ================
-oz-viewer-devreview.build_debug_release_separately = true
-viewer-devreview.build_debug_release_separately = true
-oz_viewer-poreview.build_debug_release_separately = true
-oz-project-1.build_debug_release_separately = true
-oz-project-2.build_debug_release_separately = true
-oz-project-3.build_debug_release_separately = true
+oz_viewer-devreview.build_debug_release_separately = true
+oz_project-1.build_debug_release_separately = true
+oz_project-2.build_debug_release_separately = true
+oz_project-3.build_debug_release_separately = true
# ========================================
# enus
diff --git a/autobuild.xml b/autobuild.xml
index c79701adfd..c79701adfd 100755..100644
--- a/autobuild.xml
+++ b/autobuild.xml
diff --git a/build.sh b/build.sh
index 937c1f27ab..937c1f27ab 100644..100755
--- a/build.sh
+++ b/build.sh
diff --git a/doc/contributions.txt b/doc/contributions.txt
index e355dcabab..08612a4e7d 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -1,887 +1,896 @@
-Linden Lab would like to acknowledge source code contributions from the
-following residents. The Second Life resident name is given below,
-along with the issue identifier corresponding to the patches we've
-received from them.
-
-Able Whitman
- VWR-650
- VWR-1460
- VWR-1691
- VWR-1735
- VWR-1813
-Adam Marker
- VWR-2755
-Agathos Frascati
- CT-246
- CT-317
- CT-352
-Aimee Trescothick
- SNOW-227
- SNOW-570
- SNOW-572
- SNOW-575
- VWR-3321
- VWR-3336
- VWR-3903
- VWR-4083
- VWR-4106
- VWR-5308
- VWR-6348
- VWR-6358
- VWR-6360
- VWR-6432
- VWR-6550
- VWR-6583
- VWR-6482
- VWR-6918
- VWR-7109
- VWR-7383
- VWR-7800
- VWR-8008
- VWR-8341
- VWR-8430
- VWR-8482
- VWR-9255
- VWR-10717
- VWR-10990
- VWR-11100
- VWR-11111
- VWR-11844
- VWR-12631
- VWR-12696
- VWR-12748
- VWR-13221
- VWR-14087
- VWR-14267
- VWR-14278
- VWR-14711
- VWR-14712
- VWR-15454
-Alejandro Rosenthal
- VWR-1184
-Aleric Inglewood
- SNOW-240
- SNOW-522
- SNOW-626
- SNOW-756
- SNOW-764
- SNOW-800
- VWR-10001
- VWR-10579
- VWR-10759
- VWR-10837
- VWR-12691
- VWR-12984
- VWR-13040
- VWR-13996
- VWR-14426
- VWR-24247
- VWR-24251
- VWR-24252
- VWR-24254
- VWR-24261
- VWR-24315
- VWR-24317
- VWR-24320
- VWR-24321
- VWR-24337
- VWR-24354
- VWR-24366
- VWR-24519
- VWR-24520
- SNOW-84
- SNOW-477
- SNOW-744
- SNOW-766
- STORM-163
- STORM-955
- STORM-960
-Ales Beaumont
- VWR-9352
- SNOW-240
-Alexandrea Fride
- STORM-255
- STORM-960
-Alissa Sabre
- VWR-81
- VWR-83
- VWR-109
- VWR-157
- VWR-171
- VWR-177
- VWR-213
- VWR-250
- VWR-251
- VWR-286
- VWR-414
- VWR-415
- VWR-459
- VWR-606
- VWR-652
- VWR-738
- VWR-1109
- VWR-1351
- VWR-1353
- VWR-1410
- VWR-1843
- VWR-2116
- VWR-2826
- VWR-3290
- VWR-3410
- VWR-3857
- VWR-4010
- VWR-5575
- VWR-5717
- VWR-5929
- VWR-6384
- VWR-6385
- VWR-6386
- VWR-6430
- VWR-6858
- VWR-6668
- VWR-7086
- VWR-7087
- VWR-7153
- VWR-7168
- VWR-9190
- VWR-10728
- VWR-11172
- VWR-12569
- VWR-12617
- VWR-12620
- VWR-12789
- SNOW-322
-Angus Boyd
- VWR-592
-Ann Congrejo
- CT-193
-Ardy Lay
- VWR-19499
- VWR-24917
-Argent Stonecutter
- VWR-68
-Armin Weatherwax
- VWR-8436
-Asuka Neely
- VWR-3434
- VWR-8179
-Balp Allen
- VWR-4157
-Be Holder
- SNOW-322
- SNOW-397
-Benja Kepler
- VWR-746
-Biancaluce Robbiani
- CT-225
- CT-226
- CT-227
- CT-228
- CT-229
- CT-230
- CT-231
- CT-321
- CT-352
-Blakar Ogre
- VWR-418
- VWR-881
- VWR-983
- VWR-1612
- VWR-1613
- VWR-2164
-blino Nakamura
- VWR-17
-Boroondas Gupte
- OPEN-29
- OPEN-39
- OPEN-39
- SNOW-278
- SNOW-503
- SNOW-510
- SNOW-527
- SNOW-610
- SNOW-624
- SNOW-737
- STORM-318
- VWR-233
- VWR-20583
- VWR-20891
- VWR-23455
- VWR-24487
- WEB-262
-Bulli Schumann
- CT-218
- CT-219
- CT-220
- CT-221
- CT-222
- CT-223
- CT-224
- CT-319
- CT-350
- CT-352
-bushing Spatula
- VWR-119
- VWR-424
-Carjay McGinnis
- VWR-3737
- VWR-4070
- VWR-4212
- VWR-6154
- VWR-9400
- VWR-9620
-Catherine Pfeffer
- VWR-1282
- VWR-8624
- VWR-10854
-Celierra Darling
- VWR-1274
- VWR-6975
-Coaldust Numbers
- VWR-1095
-Cron Stardust
- VWR-10579
- VWR-25120
-Cypren Christenson
- STORM-417
-Dale Glass
- VWR-120
- VWR-560
- VWR-2502
- VWR-1358
- VWR-2041
-Drew Dri
- VWR-19683
-Drewan Keats
- VWR-28
- VWR-248
- VWR-412
- VWR-638
- VWR-660
-Dylan Haskell
- VWR-72
-Dzonatas Sol
- VWR-187
- VWR-198
- VWR-777
- VWR-878
- VWR-962
- VWR-975
- VWR-1061
- VWR-1062
- VWR-1704
- VWR-1705
- VWR-1729
- VWR-1812
-Eddi Decosta
- SNOW-586
-Eddy Stryker
- VWR-15
- VWR-23
- VWR-1468
- VWR-1475
-EponymousDylan Ra
- VWR-1289
- VWR-1465
-Eva Nowicka
- CT-324
- CT-352
-Farallon Greyskin
- VWR-2036
-Feep Larsson
- VWR-447
- VWR-1314
- VWR-4444
-Flemming Congrejo
- CT-193
- CT-318
-Fluf Fredriksson
- VWR-3450
-Fremont Cunningham
- VWR-1147
-Geneko Nemeth
- CT-117
- VWR-11069
-Gigs Taggart
- SVC-493
- VWR-6
- VWR-38
- VWR-71
- VWR-101
- VWR-166
- VWR-234
- VWR-315
- VWR-326
- VWR-442
- VWR-493
- VWR-1203
- VWR-1217
- VWR-1434
- VWR-1987
- VWR-2065
- VWR-2491
- VWR-2502
- VWR-2331
- VWR-5308
- VWR-8781
- VWR-8783
-Ginko Bayliss
- VWR-4
-Grazer Kline
- VWR-1092
- VWR-2113
-Gudmund Shepherd
- VWR-1594
- VWR-1873
-Hamncheese Omlet
- VWR-333
-HappySmurf Papp
- CT-193
-Henri Beauchamp
- VWR-1320
- VWR-1406
- VWR-4157
-Hikkoshi Sakai
- VWR-429
-Hiro Sommambulist
- VWR-66
- VWR-67
- VWR-97
- VWR-100
- VWR-105
- VWR-118
- VWR-132
- VWR-136
- VWR-143
-Hoze Menges
- VWR-255
-Ian Kas
- VWR-8780 (Russian localization)
- [NO JIRA] (Ukranian localization)
- CT-322
- CT-325
-Irene Muni
- CT-324
- CT-352
-Iskar Ariantho
- VWR-1223
- VWR-11759
-Jacek Antonelli
- SNOW-388
- VWR-165
- VWR-188
- VWR-427
- VWR-597
- VWR-2054
- VWR-2448
- VWR-2896
- VWR-2947
- VWR-2948
- VWR-3605
- VWR-8617
-JB Kraft
- VWR-5283
- VWR-7802
-Joghert LeSabre
- VWR-64
-Jonathan Yap
- STORM-435
- STORM-523
- STORM-596
- STORM-615
- STORM-616
- STORM-643
- STORM-679
- STORM-723
- STORM-726
- STORM-737
- STORM-785
- STORM-812
- STORM-829
- STORM-844
- STORM-953
- STORM-954
- STORM-960
- STORM-869
- STORM-974
- STORM-975
- STORM-977
- STORM-979
- STORM-980
- STORM-1040
- VWR-17801
- VWR-24347
- STORM-975
- STORM-990
- STORM-1019
- STORM-844
- STORM-643
- STORM-1020
- STORM-1064
- STORM-960
- STORM-1077
- STORM-953
-Kage Pixel
- VWR-11
-Ken March
- CT-245
-Kerutsen Sellery
- VWR-1350
-Khyota Wulluf
- VWR-2085
- VWR-8885
- VWR-9256
- VWR-9966
-Kitty Barnett
- VWR-19699
- STORM-288
- STORM-799
- STORM-800
- STORM-1001
- VWR-24217
-Kunnis Basiat
- VWR-82
- VWR-102
-Latif Khalifa
- VWR-5370
-Lisa Lowe
- CT-218
- CT-219
- CT-220
- CT-221
- CT-222
- CT-223
- CT-224
- CT-319
-Lockhart Cordoso
- VWR-108
-maciek marksman
- CT-86
-Magnus Balczo
- CT-138
-Malwina Dollinger
- CT-138
-march Korda
- SVC-1020
-Marine Kelley
- STORM-281
-Matthew Dowd
- VWR-1344
- VWR-1651
- VWR-1736
- VWR-1737
- VWR-1761
- VWR-2681
-McCabe Maxsted
- SNOW-387
- VWR-1318
- VWR-4065
- VWR-4826
- VWR-6518
- VWR-7827
- VWR-7877
- VWR-7893
- VWR-8080
- VWR-8454
- VWR-8689
- VWR-9007
-Michelle2 Zenovka
- STORM-477
- VWR-2652
- VWR-2662
- VWR-2834
- VWR-3749
- VWR-4022
- VWR-4331
- VWR-4506
- VWR-4981
- VWR-5082
- VWR-5659
- VWR-7831
- VWR-8885
- VWR-8889
- VWR-8310
- VWR-9499
-Mm Alder
- SNOW-376
- VWR-197
- VWR-3777
- VWR-4232
- VWR-4794
- VWR-13578
-Mr Greggan
- VWR-445
-Nicholaz Beresford
- VWR-132
- VWR-176
- VWR-193
- VWR-349
- VWR-353
- VWR-364
- VWR-374
- VWR-546
- VWR-691
- VWR-727
- VWR-793
- VWR-794
- VWR-802
- VWR-803
- VWR-804
- VWR-805
- VWR-807
- VWR-808
- VWR-809
- VWR-810
- VWR-823
- VWR-849
- VWR-856
- VWR-865
- VWR-869
- VWR-870
- VWR-871
- VWR-873
- VWR-908
- VWR-966
- VWR-1105
- VWR-1221
- VWR-1230
- VWR-1270
- VWR-1294
- VWR-1296
- VWR-1354
- VWR-1410
- VWR-1418
- VWR-1436
- VWR-1453
- VWR-1455
- VWR-1470
- VWR-1471
- VWR-1566
- VWR-1578
- VWR-1626
- VWR-1646
- VWR-1655
- VWR-1698
- VWR-1706
- VWR-1721
- VWR-1723
- VWR-1732
- VWR-1754
- VWR-1769
- VWR-1808
- VWR-1826
- VWR-1861
- VWR-1872
- VWR-1968
- VWR-2046
- VWR-2142
- VWR-2152
- VWR-2614
- VWR-2411
- VWR-2412
- VWR-2682
- VWR-2684
-Nicky Perian
- OPEN-1
- OPEN-1087
- STORM-1090
-Nounouch Hapmouche
- VWR-238
-Patric Mills
- VWR-2645
-Paul Churchill
- VWR-20
- VWR-493
- VWR-749
- VWR-1567
- VWR-1647
- VWR-1880
- VWR-2072
-Paula Innis
- VWR-30
- VWR-293
- VWR-1049
- VWR-1562
-Peekay Semyorka
- VWR-7
- VWR-19
- VWR-49
- VWR-79
-Peter Lameth
- VWR-7331
-Pf Shan
- CT-225
- CT-226
- CT-227
- CT-228
- CT-229
- CT-230
- CT-231
- CT-321
- SNOW-422
-princess niven
- VWR-5733
- CT-85
- CT-320
- CT-352
-Renault Clio
- VWR-1976
-resu Ampan
- SNOW-93
-Ringo Tuxing
- CT-225
- CT-226
- CT-227
- CT-228
- CT-229
- CT-230
- CT-231
- CT-321
-Robin Cornelius
- SNOW-108
- SNOW-204
- SNOW-287
- SNOW-484
- SNOW-504
- SNOW-506
- SNOW-507
- SNOW-511
- SNOW-512
- SNOW-514
- SNOW-520
- SNOW-585
- SNOW-599
- SNOW-747
- STORM-422
- STORM-960
- STORM-1019
- VWR-2488
- VWR-9557
- VWR-10579
- VWR-11128
- VWR-12533
- VWR-12587
- VWR-12758
- VWR-12763
- VWR-12995
- VWR-20911
-Ryozu Kojima
- VWR-53
- VWR-287
-Salahzar Stenvaag
- CT-225
- CT-226
- CT-227
- CT-228
- CT-229
- CT-230
- CT-231
- CT-321
-Sammy Frederix
- VWR-6186
-Satomi Ahn
- STORM-501
- STORM-229
-Scrippy Scofield
- VWR-3748
-Seg Baphomet
- VWR-1475
- VWR-1525
- VWR-1585
- VWR-1586
- VWR-2662
- VWR-3206
- VWR-2488
-Sergen Davies
- CT-225
- CT-226
- CT-227
- CT-228
- CT-229
- CT-230
- CT-231
- CT-321
-Shawn Kaufmat
- SNOW-240
-Siana Gearz
- STORM-960
-SignpostMarv Martin
- VWR-153
- VWR-154
- VWR-155
- VWR-218
- VWR-373
- VWR-8357
-Simon Nolan
- VWR-409
-SpacedOut Frye
- VWR-34
- VWR-45
- VWR-57
- VWR-94
- VWR-113
- VWR-121
- VWR-123
- VWR-130
- VWR-1823
-Sporked Friis
- VWR-4903
-Stevex Janus
- VWR-1182
-Still Defiant
- VWR-207
- VWR-227
- VWR-446
-Strife Onizuka
- SVC-9
- VWR-14
- VWR-74
- VWR-85
- VWR-148
- WEB-164
- VWR-183
- VWR-2265
- VWR-4111
- SNOW-691
-Tayra Dagostino
- SNOW-517
- SNOW-543
- VWR-13947
-TBBle Kurosawa
- VWR-938
- VWR-941
- VWR-942
- VWR-944
- VWR-945
- SNOW-543
- VWR-1891
- VWR-1892
-Teardrops Fall
- VWR-5366
-Techwolf Lupindo
- SNOW-92
- SNOW-592
- SNOW-649
- SNOW-650
- SNOW-651
- SNOW-654
- SNOW-687
- SNOW-680
- SNOW-681
- SNOW-685
- SNOW-690
- SNOW-746
- VWR-12385
- VWR-20893
-tenebrous pau
- VWR-247
-Tharax Ferraris
- VWR-605
-Thickbrick Sleaford
- SNOW-207
- SNOW-390
- SNOW-421
- SNOW-462
- SNOW-586
- SNOW-592
- SNOW-635
- SNOW-743
- VWR-7109
- VWR-9287
- VWR-13483
- VWR-13947
- VWR-24420
-Thraxis Epsilon
- SVC-371
- VWR-383
-tiamat bingyi
- CT-246
-Tofu Buzzard
- CTS-411
- STORM-546
- VWR-24509
-TraductoresAnonimos Alter
- CT-324
-Tue Torok
- CT-68
- CT-69
- CT-70
- CT-72
- CT-73
- CT-74
-Twisted Laws
- SNOW-352
- STORM-466
- STORM-467
- STORM-844
- STORM-643
- STORM-954
-Vadim Bigbear
- VWR-2681
-Vector Hastings
- VWR-8726
-Vixen Heron
- VWR-2710
- CT-88
-Whoops Babii
- VWR-631
- VWR-1640
- VWR-3340
- SNOW-667
- VWR-4800
- VWR-4802
- VWR-4804
- VWR-4805
- VWR-4806
- VWR-4808
- VWR-4809
- VWR-4811
- VWR-4815
- VWR-4816
- VWR-4818
- VWR-5659
- VWR-8291
- VWR-8292
- VWR-8293
- VWR-8294
- VWR-8295
- VWR-8296
- VWR-8297
- VWR-8298
-Wilton Lundquist
- VWR-7682
-WolfPup Lowenhar
- OPEN-1
- OPEN-37
- SNOW-622
- SNOW-772
- STORM-102
- STORM-103
- STORM-143
- STORM-236
- STORM-255
- STORM-256
- STORM-288
- STORM-535
- STORM-544
- STORM-654
- STORM-674
- STORM-776
- STORM-825
- VWR-20741
- VWR-20933
-Zai Lynch
- VWR-19505
-Zarkonnen Decosta
- VWR-253
-Zi Ree
- VWR-423
- VWR-671
- VWR-682
- VWR-684
- VWR-9127
- VWR-1140
-Zipherius Turas
- VWR-76
- VWR-77
-
+Linden Lab would like to acknowledge source code contributions from the
+following residents. The Second Life resident name is given below,
+along with the issue identifier corresponding to the patches we've
+received from them.
+
+Able Whitman
+ VWR-650
+ VWR-1460
+ VWR-1691
+ VWR-1735
+ VWR-1813
+Adam Marker
+ VWR-2755
+Agathos Frascati
+ CT-246
+ CT-317
+ CT-352
+Aimee Trescothick
+ SNOW-227
+ SNOW-570
+ SNOW-572
+ SNOW-575
+ VWR-3321
+ VWR-3336
+ VWR-3903
+ VWR-4083
+ VWR-4106
+ VWR-5308
+ VWR-6348
+ VWR-6358
+ VWR-6360
+ VWR-6432
+ VWR-6550
+ VWR-6583
+ VWR-6482
+ VWR-6918
+ VWR-7109
+ VWR-7383
+ VWR-7800
+ VWR-8008
+ VWR-8341
+ VWR-8430
+ VWR-8482
+ VWR-9255
+ VWR-10717
+ VWR-10990
+ VWR-11100
+ VWR-11111
+ VWR-11844
+ VWR-12631
+ VWR-12696
+ VWR-12748
+ VWR-13221
+ VWR-14087
+ VWR-14267
+ VWR-14278
+ VWR-14711
+ VWR-14712
+ VWR-15454
+Alejandro Rosenthal
+ VWR-1184
+Aleric Inglewood
+ SNOW-240
+ SNOW-522
+ SNOW-626
+ SNOW-756
+ SNOW-764
+ SNOW-800
+ VWR-10001
+ VWR-10579
+ VWR-10759
+ VWR-10837
+ VWR-12691
+ VWR-12984
+ VWR-13040
+ VWR-13996
+ VWR-14426
+ VWR-24247
+ VWR-24251
+ VWR-24252
+ VWR-24254
+ VWR-24261
+ VWR-24315
+ VWR-24317
+ VWR-24320
+ VWR-24321
+ VWR-24337
+ VWR-24354
+ VWR-24366
+ VWR-24519
+ VWR-24520
+ SNOW-84
+ SNOW-477
+ SNOW-744
+ SNOW-766
+ STORM-163
+ STORM-955
+ STORM-960
+Ales Beaumont
+ VWR-9352
+ SNOW-240
+Alexandrea Fride
+ STORM-255
+ STORM-960
+Alissa Sabre
+ VWR-81
+ VWR-83
+ VWR-109
+ VWR-157
+ VWR-171
+ VWR-177
+ VWR-213
+ VWR-250
+ VWR-251
+ VWR-286
+ VWR-414
+ VWR-415
+ VWR-459
+ VWR-606
+ VWR-652
+ VWR-738
+ VWR-1109
+ VWR-1351
+ VWR-1353
+ VWR-1410
+ VWR-1843
+ VWR-2116
+ VWR-2826
+ VWR-3290
+ VWR-3410
+ VWR-3857
+ VWR-4010
+ VWR-5575
+ VWR-5717
+ VWR-5929
+ VWR-6384
+ VWR-6385
+ VWR-6386
+ VWR-6430
+ VWR-6858
+ VWR-6668
+ VWR-7086
+ VWR-7087
+ VWR-7153
+ VWR-7168
+ VWR-9190
+ VWR-10728
+ VWR-11172
+ VWR-12569
+ VWR-12617
+ VWR-12620
+ VWR-12789
+ SNOW-322
+Angus Boyd
+ VWR-592
+Ann Congrejo
+ CT-193
+Ansariel Hiller
+ STORM-1101
+Ardy Lay
+ VWR-19499
+ VWR-24917
+Argent Stonecutter
+ VWR-68
+Armin Weatherwax
+ VWR-8436
+Asuka Neely
+ VWR-3434
+ VWR-8179
+Balp Allen
+ VWR-4157
+Be Holder
+ SNOW-322
+ SNOW-397
+Benja Kepler
+ VWR-746
+Biancaluce Robbiani
+ CT-225
+ CT-226
+ CT-227
+ CT-228
+ CT-229
+ CT-230
+ CT-231
+ CT-321
+ CT-352
+Blakar Ogre
+ VWR-418
+ VWR-881
+ VWR-983
+ VWR-1612
+ VWR-1613
+ VWR-2164
+blino Nakamura
+ VWR-17
+Boroondas Gupte
+ OPEN-29
+ OPEN-39
+ OPEN-39
+ SNOW-278
+ SNOW-503
+ SNOW-510
+ SNOW-527
+ SNOW-610
+ SNOW-624
+ SNOW-737
+ STORM-318
+ VWR-233
+ VWR-20583
+ VWR-20891
+ VWR-23455
+ VWR-24487
+ WEB-262
+Bulli Schumann
+ CT-218
+ CT-219
+ CT-220
+ CT-221
+ CT-222
+ CT-223
+ CT-224
+ CT-319
+ CT-350
+ CT-352
+bushing Spatula
+ VWR-119
+ VWR-424
+Carjay McGinnis
+ VWR-3737
+ VWR-4070
+ VWR-4212
+ VWR-6154
+ VWR-9400
+ VWR-9620
+Catherine Pfeffer
+ VWR-1282
+ VWR-8624
+ VWR-10854
+Celierra Darling
+ VWR-1274
+ VWR-6975
+Coaldust Numbers
+ VWR-1095
+Cron Stardust
+ VWR-10579
+ VWR-25120
+Cypren Christenson
+ STORM-417
+Dale Glass
+ VWR-120
+ VWR-560
+ VWR-2502
+ VWR-1358
+ VWR-2041
+Drew Dri
+ VWR-19683
+Drewan Keats
+ VWR-28
+ VWR-248
+ VWR-412
+ VWR-638
+ VWR-660
+Dylan Haskell
+ VWR-72
+Dzonatas Sol
+ VWR-187
+ VWR-198
+ VWR-777
+ VWR-878
+ VWR-962
+ VWR-975
+ VWR-1061
+ VWR-1062
+ VWR-1704
+ VWR-1705
+ VWR-1729
+ VWR-1812
+Eddi Decosta
+ SNOW-586
+Eddy Stryker
+ VWR-15
+ VWR-23
+ VWR-1468
+ VWR-1475
+EponymousDylan Ra
+ VWR-1289
+ VWR-1465
+Eva Nowicka
+ CT-324
+ CT-352
+Farallon Greyskin
+ VWR-2036
+Feep Larsson
+ VWR-447
+ VWR-1314
+ VWR-4444
+Flemming Congrejo
+ CT-193
+ CT-318
+Fluf Fredriksson
+ VWR-3450
+Fremont Cunningham
+ VWR-1147
+Geneko Nemeth
+ CT-117
+ VWR-11069
+Gigs Taggart
+ SVC-493
+ VWR-6
+ VWR-38
+ VWR-71
+ VWR-101
+ VWR-166
+ VWR-234
+ VWR-315
+ VWR-326
+ VWR-442
+ VWR-493
+ VWR-1203
+ VWR-1217
+ VWR-1434
+ VWR-1987
+ VWR-2065
+ VWR-2491
+ VWR-2502
+ VWR-2331
+ VWR-5308
+ VWR-8781
+ VWR-8783
+Ginko Bayliss
+ VWR-4
+Grazer Kline
+ VWR-1092
+ VWR-2113
+Gudmund Shepherd
+ VWR-1594
+ VWR-1873
+Hamncheese Omlet
+ VWR-333
+HappySmurf Papp
+ CT-193
+Henri Beauchamp
+ VWR-1320
+ VWR-1406
+ VWR-4157
+Hikkoshi Sakai
+ VWR-429
+Hiro Sommambulist
+ VWR-66
+ VWR-67
+ VWR-97
+ VWR-100
+ VWR-105
+ VWR-118
+ VWR-132
+ VWR-136
+ VWR-143
+Hoze Menges
+ VWR-255
+Ian Kas
+ VWR-8780 (Russian localization)
+ [NO JIRA] (Ukranian localization)
+ CT-322
+ CT-325
+Irene Muni
+ CT-324
+ CT-352
+Iskar Ariantho
+ VWR-1223
+ VWR-11759
+Jacek Antonelli
+ SNOW-388
+ VWR-165
+ VWR-188
+ VWR-427
+ VWR-597
+ VWR-2054
+ VWR-2448
+ VWR-2896
+ VWR-2947
+ VWR-2948
+ VWR-3605
+ VWR-8617
+JB Kraft
+ VWR-5283
+ VWR-7802
+Joghert LeSabre
+ VWR-64
+Jonathan Yap
+ STORM-435
+ STORM-523
+ STORM-596
+ STORM-615
+ STORM-616
+ STORM-643
+ STORM-679
+ STORM-723
+ STORM-726
+ STORM-737
+ STORM-785
+ STORM-812
+ STORM-829
+ STORM-844
+ STORM-953
+ STORM-954
+ STORM-960
+ STORM-869
+ STORM-974
+ STORM-975
+ STORM-977
+ STORM-979
+ STORM-980
+ STORM-1040
+ VWR-17801
+ VWR-24347
+ STORM-975
+ STORM-990
+ STORM-1019
+ STORM-844
+ STORM-643
+ STORM-1020
+ STORM-1064
+ STORM-960
+ STORM-1101
+ STORM-1108
+ STORM-1094
+ STORM-1077
+ STORM-953
+Kage Pixel
+ VWR-11
+Ken March
+ CT-245
+Kerutsen Sellery
+ VWR-1350
+Khyota Wulluf
+ VWR-2085
+ VWR-8885
+ VWR-9256
+ VWR-9966
+Kitty Barnett
+ VWR-19699
+ STORM-288
+ STORM-799
+ STORM-800
+ STORM-1001
+ VWR-24217
+Kunnis Basiat
+ VWR-82
+ VWR-102
+Lance Corrimal
+ VWR-25269
+Latif Khalifa
+ VWR-5370
+Lisa Lowe
+ CT-218
+ CT-219
+ CT-220
+ CT-221
+ CT-222
+ CT-223
+ CT-224
+ CT-319
+Lockhart Cordoso
+ VWR-108
+maciek marksman
+ CT-86
+Magnus Balczo
+ CT-138
+Malwina Dollinger
+ CT-138
+march Korda
+ SVC-1020
+Marine Kelley
+ STORM-281
+Matthew Dowd
+ VWR-1344
+ VWR-1651
+ VWR-1736
+ VWR-1737
+ VWR-1761
+ VWR-2681
+McCabe Maxsted
+ SNOW-387
+ VWR-1318
+ VWR-4065
+ VWR-4826
+ VWR-6518
+ VWR-7827
+ VWR-7877
+ VWR-7893
+ VWR-8080
+ VWR-8454
+ VWR-8689
+ VWR-9007
+Michelle2 Zenovka
+ STORM-477
+ VWR-2652
+ VWR-2662
+ VWR-2834
+ VWR-3749
+ VWR-4022
+ VWR-4331
+ VWR-4506
+ VWR-4981
+ VWR-5082
+ VWR-5659
+ VWR-7831
+ VWR-8885
+ VWR-8889
+ VWR-8310
+ VWR-9499
+Mm Alder
+ SNOW-376
+ VWR-197
+ VWR-3777
+ VWR-4232
+ VWR-4794
+ VWR-13578
+Mr Greggan
+ VWR-445
+Nicholaz Beresford
+ VWR-132
+ VWR-176
+ VWR-193
+ VWR-349
+ VWR-353
+ VWR-364
+ VWR-374
+ VWR-546
+ VWR-691
+ VWR-727
+ VWR-793
+ VWR-794
+ VWR-802
+ VWR-803
+ VWR-804
+ VWR-805
+ VWR-807
+ VWR-808
+ VWR-809
+ VWR-810
+ VWR-823
+ VWR-849
+ VWR-856
+ VWR-865
+ VWR-869
+ VWR-870
+ VWR-871
+ VWR-873
+ VWR-908
+ VWR-966
+ VWR-1105
+ VWR-1221
+ VWR-1230
+ VWR-1270
+ VWR-1294
+ VWR-1296
+ VWR-1354
+ VWR-1410
+ VWR-1418
+ VWR-1436
+ VWR-1453
+ VWR-1455
+ VWR-1470
+ VWR-1471
+ VWR-1566
+ VWR-1578
+ VWR-1626
+ VWR-1646
+ VWR-1655
+ VWR-1698
+ VWR-1706
+ VWR-1721
+ VWR-1723
+ VWR-1732
+ VWR-1754
+ VWR-1769
+ VWR-1808
+ VWR-1826
+ VWR-1861
+ VWR-1872
+ VWR-1968
+ VWR-2046
+ VWR-2142
+ VWR-2152
+ VWR-2614
+ VWR-2411
+ VWR-2412
+ VWR-2682
+ VWR-2684
+Nicky Perian
+ OPEN-1
+ OPEN-1087
+ STORM-1090
+Nounouch Hapmouche
+ VWR-238
+Patric Mills
+ VWR-2645
+Paul Churchill
+ VWR-20
+ VWR-493
+ VWR-749
+ VWR-1567
+ VWR-1647
+ VWR-1880
+ VWR-2072
+Paula Innis
+ VWR-30
+ VWR-293
+ VWR-1049
+ VWR-1562
+Peekay Semyorka
+ VWR-7
+ VWR-19
+ VWR-49
+ VWR-79
+Peter Lameth
+ VWR-7331
+Pf Shan
+ CT-225
+ CT-226
+ CT-227
+ CT-228
+ CT-229
+ CT-230
+ CT-231
+ CT-321
+ SNOW-422
+princess niven
+ VWR-5733
+ CT-85
+ CT-320
+ CT-352
+Renault Clio
+ VWR-1976
+resu Ampan
+ SNOW-93
+Ringo Tuxing
+ CT-225
+ CT-226
+ CT-227
+ CT-228
+ CT-229
+ CT-230
+ CT-231
+ CT-321
+Robin Cornelius
+ SNOW-108
+ SNOW-204
+ SNOW-287
+ SNOW-484
+ SNOW-504
+ SNOW-506
+ SNOW-507
+ SNOW-511
+ SNOW-512
+ SNOW-514
+ SNOW-520
+ SNOW-585
+ SNOW-599
+ SNOW-747
+ STORM-422
+ STORM-960
+ STORM-1019
+ VWR-2488
+ VWR-9557
+ VWR-10579
+ VWR-11128
+ VWR-12533
+ VWR-12587
+ VWR-12758
+ VWR-12763
+ VWR-12995
+ VWR-20911
+Ryozu Kojima
+ VWR-53
+ VWR-287
+Salahzar Stenvaag
+ CT-225
+ CT-226
+ CT-227
+ CT-228
+ CT-229
+ CT-230
+ CT-231
+ CT-321
+Sammy Frederix
+ VWR-6186
+Satomi Ahn
+ STORM-501
+ STORM-229
+Scrippy Scofield
+ VWR-3748
+Seg Baphomet
+ VWR-1475
+ VWR-1525
+ VWR-1585
+ VWR-1586
+ VWR-2662
+ VWR-3206
+ VWR-2488
+Sergen Davies
+ CT-225
+ CT-226
+ CT-227
+ CT-228
+ CT-229
+ CT-230
+ CT-231
+ CT-321
+Shawn Kaufmat
+ SNOW-240
+Siana Gearz
+ STORM-960
+SignpostMarv Martin
+ VWR-153
+ VWR-154
+ VWR-155
+ VWR-218
+ VWR-373
+ VWR-8357
+Simon Nolan
+ VWR-409
+SpacedOut Frye
+ VWR-34
+ VWR-45
+ VWR-57
+ VWR-94
+ VWR-113
+ VWR-121
+ VWR-123
+ VWR-130
+ VWR-1823
+Sporked Friis
+ VWR-4903
+Stevex Janus
+ VWR-1182
+Still Defiant
+ VWR-207
+ VWR-227
+ VWR-446
+Strife Onizuka
+ SVC-9
+ VWR-14
+ VWR-74
+ VWR-85
+ VWR-148
+ WEB-164
+ VWR-183
+ VWR-2265
+ VWR-4111
+ SNOW-691
+Tayra Dagostino
+ SNOW-517
+ SNOW-543
+ VWR-13947
+TBBle Kurosawa
+ VWR-938
+ VWR-941
+ VWR-942
+ VWR-944
+ VWR-945
+ SNOW-543
+ VWR-1891
+ VWR-1892
+Teardrops Fall
+ VWR-5366
+Techwolf Lupindo
+ SNOW-92
+ SNOW-592
+ SNOW-649
+ SNOW-650
+ SNOW-651
+ SNOW-654
+ SNOW-687
+ SNOW-680
+ SNOW-681
+ SNOW-685
+ SNOW-690
+ SNOW-746
+ VWR-12385
+ VWR-20893
+tenebrous pau
+ VWR-247
+Tharax Ferraris
+ VWR-605
+Thickbrick Sleaford
+ SNOW-207
+ SNOW-390
+ SNOW-421
+ SNOW-462
+ SNOW-586
+ SNOW-592
+ SNOW-635
+ SNOW-743
+ VWR-7109
+ VWR-9287
+ VWR-13483
+ VWR-13947
+ VWR-24420
+ STORM-1147
+Thraxis Epsilon
+ SVC-371
+ VWR-383
+tiamat bingyi
+ CT-246
+Tofu Buzzard
+ CTS-411
+ STORM-546
+ VWR-24509
+TraductoresAnonimos Alter
+ CT-324
+Tue Torok
+ CT-68
+ CT-69
+ CT-70
+ CT-72
+ CT-73
+ CT-74
+Twisted Laws
+ SNOW-352
+ STORM-466
+ STORM-467
+ STORM-844
+ STORM-643
+ STORM-954
+Vadim Bigbear
+ VWR-2681
+Vector Hastings
+ VWR-8726
+Vixen Heron
+ VWR-2710
+ CT-88
+Whoops Babii
+ VWR-631
+ VWR-1640
+ VWR-3340
+ SNOW-667
+ VWR-4800
+ VWR-4802
+ VWR-4804
+ VWR-4805
+ VWR-4806
+ VWR-4808
+ VWR-4809
+ VWR-4811
+ VWR-4815
+ VWR-4816
+ VWR-4818
+ VWR-5659
+ VWR-8291
+ VWR-8292
+ VWR-8293
+ VWR-8294
+ VWR-8295
+ VWR-8296
+ VWR-8297
+ VWR-8298
+Wilton Lundquist
+ VWR-7682
+WolfPup Lowenhar
+ OPEN-1
+ OPEN-37
+ SNOW-622
+ SNOW-772
+ STORM-102
+ STORM-103
+ STORM-143
+ STORM-236
+ STORM-255
+ STORM-256
+ STORM-288
+ STORM-535
+ STORM-544
+ STORM-654
+ STORM-674
+ STORM-776
+ STORM-825
+ STORM-1098
+ VWR-20741
+ VWR-20933
+Zai Lynch
+ VWR-19505
+Zarkonnen Decosta
+ VWR-253
+Zi Ree
+ VWR-423
+ VWR-671
+ VWR-682
+ VWR-684
+ VWR-9127
+ VWR-1140
+Zipherius Turas
+ VWR-76
+ VWR-77
+
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 8e185df191..8e185df191 100755..100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake
index cb5124812d..cb5124812d 100644..100755
--- a/indra/cmake/FMOD.cmake
+++ b/indra/cmake/FMOD.cmake
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index e68d16ed08..e68d16ed08 100755..100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
diff --git a/indra/cmake/LLTestCommand.cmake b/indra/cmake/LLTestCommand.cmake
index b5a0580a90..b5a0580a90 100755..100644
--- a/indra/cmake/LLTestCommand.cmake
+++ b/indra/cmake/LLTestCommand.cmake
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index 748c8c2bec..748c8c2bec 100755..100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py
index 320a9be8ab..320a9be8ab 100644..100755
--- a/indra/cmake/run_build_test.py
+++ b/indra/cmake/run_build_test.py
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/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 2b25f2fabb..2b25f2fabb 100755..100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
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/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 5af1122451..5af1122451 100755..100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 23f4b5cb42..23f4b5cb42 100755..100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
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/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h
index b170ebbcd7..b170ebbcd7 100755..100644
--- a/indra/llvfs/lldir_win32.h
+++ b/indra/llvfs/lldir_win32.h
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..100644
--- 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..100644
--- 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/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi
index b5d43021ec..b5d43021ec 100755..100644
--- a/indra/newview/installers/windows/installer_template.nsi
+++ b/indra/newview/installers/windows/installer_template.nsi
diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi
index da0d7f54d2..da0d7f54d2 100755..100644
--- a/indra/newview/installers/windows/lang_en-us.nsi
+++ b/indra/newview/installers/windows/lang_en-us.nsi
Binary files differ
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 3f1bf4c5c2..790f98e75d 100755..100644
--- 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/llagentpilot.cpp b/indra/newview/llagentpilot.cpp
index 734c502fcf..734c502fcf 100755..100644
--- a/indra/newview/llagentpilot.cpp
+++ b/indra/newview/llagentpilot.cpp
diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h
index dd1709ec0c..dd1709ec0c 100755..100644
--- a/indra/newview/llagentpilot.h
+++ b/indra/newview/llagentpilot.h
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 643c611b30..5dc803e287 100755..100644
--- 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/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 35712163eb..35712163eb 100755..100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
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/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index cdd2bcf8e3..cdd2bcf8e3 100755..100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 186bf114d1..186bf114d1 100755..100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
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/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index e20e918a2a..e20e918a2a 100755..100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
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..100644
--- 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..100644
--- 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/llviewerstats.h b/indra/newview/llviewerstats.h
index f91a1241fe..f91a1241fe 100755..100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5cd2881e2a..af06421bf9 100755..100644
--- 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..100644
--- 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_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index d08c3e7078..d08c3e7078 100755..100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
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;
}
}
diff --git a/install.xml b/install.xml
new file mode 100644
index 0000000000..9658a4195a
--- /dev/null
+++ b/install.xml
@@ -0,0 +1,1898 @@
+<?xml version="1.0" ?>
+<llsd>
+<map>
+ <key>installables</key>
+ <map>
+ <key>GL</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 1991-2000 Silicon Graphics, Inc.</string>
+ <key>description</key>
+ <string>A standard for 3D Graphics rendering engine.</string>
+ <key>license</key>
+ <string>GL</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>0bd2795a2afe09f6c563f2f888f24cc9</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-darwin-20080613.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>2ab29212a7f3acdaebf10059af816be0</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>9c3dff3817f1105f9054401fdef1fe50</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>91155239b02f576384603795d41eb971</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-windows-20090505.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>SDL</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga</string>
+ <key>description</key>
+ <string>The Simple DirectMedia Layer libraries are used for handling input and basic window/GL setup on the Linux client. Packages also include cursors.</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>fce0ff7d2cdf0f36c1647e6a3916e29e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.12-linux-20090218.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>apr_suite</key>
+ <map>
+ <key>license</key>
+ <string>apache 2.0</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>115d8ac44a91efdb173e9b3e478c46b6</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.7-darwin-20090805.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>7b84cd6a3c601a104d9c09e58ef2f50c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>1a7e1186855d48d8316ce86803095f70</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-linux64-20080909a.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>a02619c1e30a3db02d3883bf1ad7a1e6</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.8-windows-20090911.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>ares</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright 1998 by the Massachusetts Institute of Technology.</string>
+ <key>description</key>
+ <string>Performs DNS requests and name resolves asynchronously. Used with libcurl to keep all HTTP operations async.</string>
+ <key>license</key>
+ <string>c-ares</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>cdb2f5c4a5a1f9ecd75bc1dbdd4db8e9</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-darwin-20100606.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>91694429e391efeea1de974df26032a2</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-linux-20100527.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>c4242416e0b2e642c0bf062a19a250e4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.3.0-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>4b84738eec2e21b0c096d53b79ee2681</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-windows-20100611a.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>artwork-common</key>
+ <map>
+ <key>copyright</key>
+ <string>(C) 2008 Linden Research, Inc.</string>
+ <key>description</key>
+ <string>Second Life(TM) Viewer Artwork</string>
+ <key>license</key>
+ <string>artwork</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>5e047437d73d1017bf270a6c6e936f23</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>5e047437d73d1017bf270a6c6e936f23</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>5e047437d73d1017bf270a6c6e936f23</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>berkeley</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 1990-1999 Sleepycat Software. All rights reserved.</string>
+ <key>description</key>
+ <string>a high-performance, embedded database library</string>
+ <key>license</key>
+ <string>sleepycat</string>
+ </map>
+ <key>boost</key>
+ <map>
+ <key>copyright</key>
+ <string>various</string>
+ <key>description</key>
+ <string>A set of portable C++ libraries which provide a wide set of functionality. </string>
+ <key>license</key>
+ <string>boost</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>71defd179827bf172b76d6020023e0e8</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-darwin-20100222a.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>4db3d74e40d149eeec06f4d97a609bb1</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux-20100624.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>af4badd6b2c10bc4db82ff1256695892</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux64-20100119.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>72e6e2eff5d146a107f3059b6c31fb95</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-windows-20100630.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>curl</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 1996 - 2008, Daniel Stenberg, &lt;daniel@haxx.se&gt;.</string>
+ <key>description</key>
+ <string>Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources. </string>
+ <key>license</key>
+ <string>curl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>ca8f0134fa5ab6f34a6eeb8d0896c9b0</string>
+ <key>url</key>
+ <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Darwin/installer/curl-7.21.1-darwin-20101214.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>9c9b629b62bf874d550c430ad678dc04</string>
+ <key>url</key>
+ <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Linux/installer/curl-7.21.1-linux-20101215.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>6994192cea7ab2d885a158a3de474273</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.16.4a-linux64-20090303.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>48691883065a82d53691d73aae81d4c1</string>
+ <key>url</key>
+ <uri>https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/CYGWIN/installer/curl-7.21.1-windows-20101214.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>dbghelp</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright Microsoft Corporation</string>
+ <key>description</key>
+ <string>dbghelp: Debug helper from Microsoft Debugging Tools For Windows</string>
+ <key>license</key>
+ <string>MSDTW</string>
+ <key>packages</key>
+ <map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>b7563064037e032143ca2d610aae5153</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbghelp-6.11.1.404-windows-20090520.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>dbusglib</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.</string>
+ <key>description</key>
+ <string>dbus/dbus-glib: headers only</string>
+ <key>license</key>
+ <string>AFL2.1</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>eb25444142d4102b0ce1b7ffaadb071e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbusglib-linux-20080707.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>elfio</key>
+ <map>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>82ea408af2f968cfe5f013ab241323ef</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/elfio-1.0.3-linux-20080812.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>expat</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd</string>
+ <key>description</key>
+ <string>An XML parser library written in C. It is a stream-oriented parser in which an application registers handlers for things the parser might find in the XML document (like start tags).</string>
+ <key>license</key>
+ <string>mit</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>c457a0a041ac4946265889a503d26c3d</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20090805.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>67b470fd446b08c9831d1039674eae4e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>278c61871419b9a4d50a4f88b7922403</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>5dbbdb4a9b5bec86d180ef20a5f8ccfb</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20090917.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>fmod</key>
+ <map>
+ <key>copyright</key>
+ <string>FMOD Sound System, copyright (C) Firelight Technologies Pty, Ltd., 1994-2006.</string>
+ <key>description</key>
+ <string>Audio engine and mp3 stream decoder .</string>
+ <key>license</key>
+ <string>fmod</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>261bcd3387066cf0a1d46549400052b5</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-darwin-20101007.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>8490d97430c12c2e1ac19ff80a8d4db4</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-linux-20101007.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>bab1babcb01ff9849b7f072d352e1ecd</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-windows-20101007.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>fontconfig</key>
+ <map>
+ <key>license</key>
+ <string>mit</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>9af6a1ed39fa540bfcaa402b0ea22f78</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/fontconfig-2.2.3-linux-20080613.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>freeglut</key>
+ <map>
+ <key>license</key>
+ <string>mit</string>
+ <key>packages</key>
+ <map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>fcbb695ff203775fad96d184bf5f34fc</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freeglut-2.4.0-windows-20090608.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>freetype</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright</string>
+ <key>description</key>
+ <string>Font</string>
+ <key>license</key>
+ <string>freetype</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>f00144dfb597140f328774c3244f0c3e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-darwin-20090922.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>9de3f44be65645c7f6af236139596942</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-linux-2010-02-19a-nommap.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>35f6fa557ba90f9cda0a18d1af2055a4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.1.5-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>88980fd6d91ac541b62dea877ebe6ba6</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-windows-20090917.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>glh_linear</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2000 Cass Everitt; Copyright (c) 2000 NVIDIA Corporation; All rights reserved.</string>
+ <key>description</key>
+ <string>nVidia NVParse SDK: platform-indepenedent C++ Apple OpenGL helper library</string>
+ <key>license</key>
+ <string>glh_linear</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>23bd9a75e5a2365a827461e6c324f52b</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-darwin-20080613.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>23bd9a75e5a2365a827461e6c324f52b</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>2965646aea1d2a6aec1fbc431c02733f</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-linux-20080613.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>38b9ddfe8dceff55ee4351016a937d1b</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-windows-20080613.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>glib</key>
+ <map>
+ <key>description</key>
+ <string>GLib is a library containing many useful C routines for things such as trees, hashes, and lists.</string>
+ <key>license</key>
+ <string>gpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>6cc5ce1fafd10299fdb890b3d4c3cf53</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-darwin-20080817.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>2f1a9e14f9213c2c9564c1c1cfdd6d47</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-linux-20080817.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>3d5e29d444dde4815b36082eedfc775a</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-windows-20080817.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>glui</key>
+ <map>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>84f792a860691d0fad6d1de6eeb31baa</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.36-darwin-20090623a.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>5b8631fe510d4ebaeb965c673937e1e7</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.3.6-windows-freeglut-20090608.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>google</key>
+ <map>
+ <key>license</key>
+ <string>mit</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>40db900872612615e849f17cbdfd2c27</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google-linux-20080812.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>google-perftools</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2005, Google Inc.</string>
+ <key>description</key>
+ <string>Heap performance and validity checking tools from google. Includes TCMalloc, heap-checker, heap-profiler and cpu-profiler.</string>
+ <key>license</key>
+ <string>bsd</string>
+ <key>packages</key>
+ <map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>32dba32ddd460a08e082898ebba6315c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google-perftools-1.0-windows-20090406.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>google_breakpad</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2006, Google Inc.</string>
+ <key>description</key>
+ <string>An open-source multi-platform crash reporting system </string>
+ <key>license</key>
+ <string>bsd</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>ced4010b59f1a579caa7fe3c18512499</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-darwin-20100528a.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>29c3e7dad60bbf02c811786436d99523</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-linux-20100521b.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>0859d47242990125f17eaab30bece2ff</string>
+ <key>url</key>
+ <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/google_breakpad-0.0.0-rev599-windows-20100524.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>googlemock</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright 2008, Google Inc.</string>
+ <key>description</key>
+ <string>Google C++ Mocking Framework (or Google Mock for short) is a library for writing and using C++ mock classes.</string>
+ <key>license</key>
+ <string>bsd</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>4863e9fea433d0a4be761ea5d3e8346a</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-darwin-20090626.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>877dabecf84339690191c6115c76366e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-linux32-20090527.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>f601a82ea91030974072da8924cae41e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-windows-20090921.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>gstreamer</key>
+ <map>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>c829b638b6eef71ca63418cb9aea46a2</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gstreamer-linux-20080613.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>befc7520fe01250f39458f65c29bc584</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gstreamer-linux64-20080909.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>gtk-atk-pango-glib</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald</string>
+ <key>description</key>
+ <string>Libraries associated with GTK for gui features. atk: interfaces for accessibility; glib: low-level core functionality for using GTK+ and GNOME; pango: layout/rendering of text w/ emphasis on internationalization.</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>21c16a74f8fc9a62e3ab944a6eb7403d</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-linux-20080616.tar.bz</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>d963750bcd333a108b3697d220c87d09</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-windows-20080613.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>havok</key>
+ <map>
+ <key>copyright</key>
+ <string>on file</string>
+ <key>description</key>
+ <string>Physics engine for the simulator</string>
+ <key>license</key>
+ <string>havok</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>f64c08771a4fc456db2a55b47302078b</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>af7b1fc9072443009f19e43fb3c8342f</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-linux-20081029.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>cd4076d6caf5fabff36bf48bd01e4ba8</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-linux64-20081030.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>f25fbb29c2275267233c79f0c68ca37f</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-windows-20081030.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>jpeglib</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2003, Yves Piguet.</string>
+ <key>description</key>
+ <string>An open-source JPEG (JFIF) library</string>
+ <key>license</key>
+ <string>jpeglib</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>8d38d74c481e9aab4518c8f2a7d52800</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>8aa8e01e0c21f60f0ede0ffb04e9214f</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-linux-20081218.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>0e7facf7d48531d20c0cd6a3c3f04021</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>6a6bb0143a2561e3276dab4bcfa425ef</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20090917a.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>jsoncpp</key>
+ <map>
+ <key>copyright</key>
+ <string>json-cpp library released to Public Domain by Baptiste Lepilleur &lt;blep@users.sourceforge.net&gt;</string>
+ <key>description</key>
+ <string>jsoncpp is an implementation of a JSON (http://json.org) reader and writer in C++.</string>
+ <key>license</key>
+ <string>jsoncpp</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>4c6b949778099a63550898f00f3e6a5e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-darwin-20090923.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>a2a94b8ca1d32f23e3e668d64023514e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-linux-20090922.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>a06ab38628ab7b53b8f3326cd942a6a8</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-linux64-20090922.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>caf152cfc730737c124f7612cf68fbd3</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-windows-20090922.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>kdu</key>
+ <map>
+ <key>copyright</key>
+ <string>on file</string>
+ <key>description</key>
+ <string>Kakadu (KDU) JPEG-2000 decoder library. </string>
+ <key>license</key>
+ <string>kdu</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>8261994de5af6581e08c26fefe1b2810</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-darwin-20101123.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>ed3e58899a424684dad49c94ba3813e7</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-linux-20101124.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>066e089a5d9faeaf131e1f4e4860a163</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-windows-20101123.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>libmono</key>
+ <map>
+ <key>copyright</key>
+ <string>(C) 2005 Novell, Inc. http://www.novell.com</string>
+ <key>description</key>
+ <string>An open source implementation of the ECMA/ISO ECMA-334 Common L\
+anguage Infrstructure (CLI) international standard</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>39a803fcbe6f11b72358fc78b7777b6c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-darwin-20080724.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>9bc0f8b7d5e0ff194b6d5635daf9ae3a</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-linux-20080816a.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>451521b4cb57c35caf3efb8dcf99b99e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-linux64-20080926.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>6712a09311a914752f47d5d62562a239</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-windows-20080903.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>libpng</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2004, 2006-2008 Glenn Randers-Pehrson</string>
+ <key>description</key>
+ <string>An open, extensible image format with lossless compression. PNG Reference Library </string>
+ <key>license</key>
+ <string>libpng</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>82659b48831cbf58bf04b86602939e0b</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-darwin-20090304.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>f5e84c991f6e3caacb26db259593cbea</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-linux-20090304.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>5ee1e62bde38520c7f134c4afb9ac9b1</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-linux64-20090304.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>c781cd9846cf20afb90ac40ad1a0ce9d</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-windows-20090917.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>libuuid</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</string>
+ <key>description</key>
+ <string>Generates UUIDs under Linux. Originally a part of the ext2fs filesystem. Also see lluuid.cpp for all platforms. Part of the e2fsprogs package.</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>91b194aed4b38bc23493b198009a8c6a</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libuuid-linux-20090417.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>libxml</key>
+ <map>
+ <key>license</key>
+ <string>mit</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>4b5d2dcfe8a49b73fb69f10aab441092</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libxml-2.6.24-linux-20080613.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>921d7f980519101afb74623e29e9d175</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libxml-2.6.24-linux64-20080909.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>llqtwebkit</key>
+ <map>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>f07b063cdc207479b111576dc74127f0</string>
+ <key>url</key>
+ <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-darwin-qt4.7.1-20110322.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>5d743c93b970abe685b185de83001a6e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20100923.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>1e66b1ecab911a60ba50b59361ef62e1</string>
+ <key>url</key>
+ <uri>http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.7.1-20110317.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>mesa</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1999-2007 Brian Paul All Rights Reserved.</string>
+ <key>description</key>
+ <string>Mesa 3-D graphics library. Provides the required Apple OpenGL headers under Linux.</string>
+ <key>license</key>
+ <string>mesa</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>70d0bbe1145fff29a0131349c898260e</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-7.0-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>56630977f9261bd82039b0da08a0685c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-6.2.1-linux64-20081016.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>82cdcdcb2d0615389a7480485ea35f4c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-7.0-windows-20080613.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>mysql</key>
+ <map>
+ <key>license</key>
+ <string>gpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>df27f2db244ea2762759a06cd75ada4e</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>cc86b4cc858655e23704d1168325d7b9</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysqlclient-linux-20090320.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>98bac06680dca907e783d8dd4aa9edde</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080804.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>ndofdev</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2007, 3Dconnexion, Inc. - All rights reserved.</string>
+ <key>description</key>
+ <string>in use on windows and darwin for joystick support.</string>
+ <key>license</key>
+ <string>linden</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>17999c47e17f2dd9e12a22372ce8ff14</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>9469c3732a33a154fa0a2807b9f36ccc</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-linux-0.2-20080828.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>f0df8a1e60991095e3adca1450b8c9c0</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20090917.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>ogg-vorbis</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 2008 Xiph.org Foundation</string>
+ <key>description</key>
+ <string>Ogg: container format Vorbis: audio compression scheme</string>
+ <key>license</key>
+ <string>ogg-vorbis</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>a6843398b780645c4897c9776c688926</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.03-1.1.2-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>6dc0536329a0aadf76e3054ffd4da61c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.2.0-linux-20081201.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>964c71e6ee22be1bcaf6d480e74cdd14</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.2.0-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>9bf1fea65e66b2cd3075e6ffd7eb57ad</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.1.3-1.2.0-windows-20080723.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>openSSL</key>
+ <map>
+ <key>license</key>
+ <string>openSSL</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>11d2be4f2b172430747b7d4a6739e3d8</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8l-darwin-20100428.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>f219ef07b02e2abb9282345c3a8f2b39</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.7c-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>00b23f28a2457d9dabbaff0b29ee7323</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8g-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>dd85209081b832e836de6e1538541d89</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8j-windows-20090129.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>openal-soft</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 2008 by authors.</string>
+ <key>description</key>
+ <string>3D Audio library</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>a0757244e3e6688fde2ffeea35cc1f96</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-darwin-20080924.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>75a7004ab14bea46594b1c652f1a6040</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-linux-20100120-3ad86a1c.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>5ad0a3ab623356c1ad61394ba238f99f</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-soft-1.6.372-linux64-20081219.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>a0757244e3e6688fde2ffeea35cc1f96</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-windows-20080924.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>openjpeg</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium</string>
+ <key>description</key>
+ <string>An open-source JPEG-2000 library; a slower alternative to Kadaku. Used in the open source release </string>
+ <key>license</key>
+ <string>openjpeg</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>23313fda213a2496945435db2a0ee78b</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3.0-darwin-20090501.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>02af0dad64803e0d821bc09e6038682c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3-linux-20081124b.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>44f1bc9d47e4a54fc274c213f2cb565f</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.2.0-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>41541a98106894e28a6bf585010fea65</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3-windows-20090407.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>pth</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (c) 1999-2006 Ralf S. Engelschall &lt;rse@gnu.org&gt;</string>
+ <key>description</key>
+ <string>Portable cooperative threads package, used to support Boost.Coroutine on Mac OS X 10.4</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>216cb6217a06c64dfae30a55ab8b975c</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-darwin-20090923.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>c5c2f73847c126e679d925beab48c7d4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux-20090427.tar.bz2</uri>
+ </map>
+ <key>linux32</key>
+ <map>
+ <key>md5sum</key>
+ <string>c5c2f73847c126e679d925beab48c7d4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux32-20090427.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>c5c2f73847c126e679d925beab48c7d4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-linux64-20090427.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>c5c2f73847c126e679d925beab48c7d4</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pth-2.0.7-windows-20090427.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>pulseaudio</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright 2004-2006 Lennart Poettering, Copyright 2006 Pierre Ossman (ossman@cendio.se) for Cendio AB</string>
+ <key>description</key>
+ <string>pulseaudio: headers only</string>
+ <key>license</key>
+ <string>lgpl</string>
+ <key>packages</key>
+ <map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>30cb00069fe2a545fbf7be1070386236</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/linux-pulse-headers-0.9.14.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>quicktime</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1990-2007 by Apple Computer, Inc., all rights reserved.</string>
+ <key>description</key>
+ <string>Separate download. Used to play in-world video clips on a prim. </string>
+ <key>license</key>
+ <string>quicktime</string>
+ <key>packages</key>
+ <map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>be45825cc14ede53790ac93c58307dcb</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/quicktime-sdk-windows-7.3-20091110.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>smartheap</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1991-2000 Compuware Corporation. All Rights Reserved.</string>
+ <key>description</key>
+ <string>Memory Management Library</string>
+ <key>license</key>
+ <string>smartheap</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>f54131b5f228e805c64c2e4e6c96579a</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-darwin-20080610.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>499208522bf7d7843e1d014d64214e06</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-linux-20080610.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>78fd47017f21d11eae43bca3e38a3e1e</string>
+ <key>url</key>
+ <uri>scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-windows-20080611.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>tut</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright 2002-2006 Vladimir Dyuzhev, Copyright 2007 Denis Kononenko, Copyright 2008 Michal Rzechonek</string>
+ <key>description</key>
+ <string>C++ Template Unit Test</string>
+ <key>license</key>
+ <string>bsd</string>
+ <key>packages</key>
+ <map>
+ <key>common</key>
+ <map>
+ <key>md5sum</key>
+ <string>a1b8a118ba9df1f2a73f6aafa7980e83</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/tut-2008-11-30-common-20081208.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>unistd</key>
+ <map>
+ <key>copyright</key>
+ <string>(c) 2008 Linden Lab.</string>
+ <key>description</key>
+ <string>Placeholder file to make flex happy on windows.</string>
+ <key>license</key>
+ <string>linden</string>
+ <key>packages</key>
+ <map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>6353aff33d7d03b22055aec76f53a866</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/unistd-windows-20080611.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>slvoice</key>
+ <map>
+ <key>copyright</key>
+ <string> </string>
+ <key>license</key>
+ <string>vivox</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>2f9b3528d4b5f858fb8dcee4b6dd5188</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-darwin-20101117a.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>cde4728b8a75a76c72a8785815cb769f</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-linux-20101117a.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>940ac55a6d0141c958bf2b14939d8474</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-windows-20101117a.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>xmlrpc-epi</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright 2000 Epinions, Inc.</string>
+ <key>description</key>
+ <string>Implementation of the xmlrpc protocol in C that provides an API for developers to serialize RPC requests to and from XML. </string>
+ <key>license</key>
+ <string>xmlrpc-epi</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>2d3a918c88d756422c1a8139ebe15f56</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-darwin-20080812.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>84a219199240ea70f54439c02acef0cd</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-linux-20080812.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>dc67b896c56116df8e18f2d1bbd07031</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>262629bcaa39dcf7266caa50da01a599</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20091016.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ <key>zlib</key>
+ <map>
+ <key>copyright</key>
+ <string>Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler</string>
+ <key>description</key>
+ <string>A Massively Spiffy Yet Delicately Unobtrusive Compression Library (Also Free, Not to Mention Unencumbered by Patents)</string>
+ <key>license</key>
+ <string>zlib</string>
+ <key>packages</key>
+ <map>
+ <key>darwin</key>
+ <map>
+ <key>md5sum</key>
+ <string>c844e1b05723ce078dbbd5aea9cdd3ad</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.1.4-darwin-20080818.tar.bz2</uri>
+ </map>
+ <key>linux</key>
+ <map>
+ <key>md5sum</key>
+ <string>26fe88213c213dc6153690ab142c25ca</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3dfsg-linux-20091208.tar.bz2</uri>
+ </map>
+ <key>linux64</key>
+ <map>
+ <key>md5sum</key>
+ <string>4bddfb2c6dd7b1470a3ed675ac14bd9a</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-linux64-20080909.tar.bz2</uri>
+ </map>
+ <key>windows</key>
+ <map>
+ <key>md5sum</key>
+ <string>73baf52a740d151fddbc2a008369c462</string>
+ <key>url</key>
+ <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-windows-20090921.tar.bz2</uri>
+ </map>
+ </map>
+ </map>
+ </map>
+ <key>licenses</key>
+ <map>
+ <key>AFL2.1</key>
+ <map>
+ <key>url</key>
+ <string>http://opensource-definition.org/licenses/afl-2.1.html</string>
+ </map>
+ <key>GL</key>
+ <map>
+ <key>url</key>
+ <string>http://www.xfree86.org/4.4.0/LICENSE9.html#sgi</string>
+ </map>
+ <key>MSDTW</key>
+ <map>
+ <key>text</key>
+ <string>MICROSOFT SOFTWARE LICENSE TERMS
+MICROSOFT DEBUGGING TOOLS FOR WINDOWS
+These license terms are an agreement between Microsoft Corporation (or based on where you live, one of
+its affiliates) and you. Please read them. They apply to the software named above, which includes the
+media on which you received it, if any. The terms also apply to any Microsoft
+* updates,
+* supplements,
+* Internet-based services
+* support services, and
+* Debugging symbol files that you may access over the internet
+for this software, unless other terms accompany those items. If so, those terms apply.
+By using the software, you accept these terms. If you do not accept them, do not use the
+software.
+If you comply with these license terms, you have the rights below.
+1. INSTALLATION AND USE RIGHTS. One user may install and use any number of copies of the
+software on your devices to design, develop, debug and test your programs.
+2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.
+a. Distributable Code. The software contains code that you are permitted to distribute in programs
+you develop if you comply with the terms below.
+i. Right to Use and Distribute. The code and text files listed below are “Distributable Code.”
+* REDIST.TXT Files. You may copy and distribute the object code form of code listed in
+REDIST.TXT files.
+* Sample Code. You may modify, copy, and distribute the source and object code form of
+code marked as “sample.”
+* Third Party Distribution. You may permit distributors of your programs to copy and
+distribute the Distributable Code as part of those programs.
+ii. Distribution Requirements. For any Distributable Code you distribute, you must
+* add significant primary functionality to it in your programs;
+* require distributors and external end users to agree to terms that protect it at least as much
+as this agreement;
+* display your valid copyright notice on your programs; and
+* indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees,
+related to the distribution or use of your programs.
+iii. Distribution Restrictions. You may not
+* alter any copyright, trademark or patent notice in the Distributable Code;
+* distribute any symbol files which you may access or use under these license terms for the
+software;
+* use Microsoft’s trademarks in your programs’ names or in a way that suggests your
+programs come from or are endorsed by Microsoft;
+* distribute Distributable Code to run on a platform other than the Windows platform;
+* include Distributable Code in malicious, deceptive or unlawful programs; or
+* modify or distribute the source code of any Distributable Code so that any part of it
+becomes subject to an Excluded License. An Excluded License is one that requires, as a
+condition of use, modification or distribution, that
+* the code be disclosed or distributed in source code form; or
+* others have the right to modify it.
+3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights
+to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights
+despite this limitation, you may use the software only as expressly permitted in this agreement. In
+doing so, you must comply with any technical limitations in the software that only allow you to use it in
+certain ways. You may not
+* work around any technical limitations in the software;
+* reverse engineer, decompile or disassemble the software, except and only to the extent that
+applicable law expressly permits, despite this limitation;
+* make more copies of the software than specified in this agreement or allowed by applicable law,
+despite this limitation;
+* publish the software for others to copy;
+* rent, lease or lend the software;
+* transfer the software or this agreement to any third party; or
+* use the software for commercial software hosting services.
+4. INTERNET-BASED SERVICES. Microsoft provides Internet-based services with the software. It may
+change or cancel them at any time.
+a. Consent for Internet-Based Services. The software contains features which may connect to
+Microsoft or service provider computer systems over the Internet. In some cases, you will not
+receive a separate notice when they connect. You may switch these features on or you may
+choose not to use them. For more information about these features, see
+http://www.microsoft.com/info/privacy/default.mspx. By using these features, you consent to the transmission of
+this information. Microsoft does not use the information to identify or contact you.
+b. Misuse of Internet-based Services. You may not use these services in any way that could
+harm them or impair anyone else’s use of them. You may not use the services to try to gain
+unauthorized access to any service, data, account or network by any means.
+
+5. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the
+software.
+6. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy
+and use the documentation for your internal, reference purposes.
+7. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You
+must comply with all domestic and international export laws and regulations that apply to the software.
+These laws include restrictions on destinations, end users and end use. For additional information, see
+www.microsoft.com/exporting.
+8. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it.
+9. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based
+services and support services that you use, are the entire agreement for the software and support
+services.
+10. APPLICABLE LAW.
+a. United States. If you acquired the software in the United States, Washington state law governs
+the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of
+laws principles. The laws of the state where you live govern all other claims, including claims under
+state consumer protection laws, unfair competition laws, and in tort.
+b. Outside the United States. If you acquired the software in any other country, the laws of that
+country apply.
+11. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the
+laws of your country. You may also have rights with respect to the party from whom you acquired the
+software. This agreement does not change your rights under the laws of your country if the laws of
+your country do not permit it to do so.
+12. DISCLAIMER OF WARRANTY. The software is licensed “as-is.” You bear the risk of using
+it. Microsoft gives no express warranties, guarantees or conditions. You may have
+additional consumer rights under your local laws which this agreement cannot change. To
+the extent permitted under your local laws, Microsoft excludes the implied warranties of
+merchantability, fitness for a particular purpose and non-infringement.
+13. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from
+Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any
+other damages, including consequential, lost profits, special, indirect or incidental
+damages.
+This limitation applies to
+* anything related to the software, services, content (including code) on third party Internet sites, or
+third party programs; and
+* claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence,
+or other tort to the extent permitted by applicable law.
+It also applies even if Microsoft knew or should have known about the possibility of the damages. The
+above limitation or exclusion may not apply to you because your country may not allow the exclusion or
+limitation of incidental, consequential or other damages.
+ </string>
+ </map>
+ <key>apache 2.0</key>
+ <map>
+ <key>url</key>
+ <string>http://www.apache.org/licenses/LICENSE-2.0</string>
+ </map>
+ <key>artwork</key>
+ <map>
+ <key>text</key>
+ <string>COPYRIGHT AND PERMISSION NOTICE
+
+Second Life(TM) Viewer Artwork. Copyright (C) 2008 Linden Research, Inc.
+
+Linden Research, Inc. ("Linden Lab") licenses the Second Life viewer
+artwork and other works in the files distributed with this Notice under
+the Creative Commons Attribution-Share Alike 3.0 License, available at
+http://creativecommons.org/licenses/by-sa/3.0/legalcode. For the license
+summary, see http://creativecommons.org/licenses/by-sa/3.0/.
+
+Notwithstanding the foregoing, all of Linden Lab's trademarks, including
+but not limited to the Second Life brand name and Second Life Eye-in-Hand
+logo, are subject to our trademark policy at
+http://secondlife.com/corporate/trademark/.
+
+If you distribute any copies or adaptations of the Second Life viewer
+artwork or any other works in these files, you must include this Notice
+and clearly identify any changes made to the original works. Include
+this Notice and information where copyright notices are usually included,
+for example, after your own copyright notice acknowledging your use of
+the Second Life viewer artwork, in a text file distributed with your
+program, in your application's About window, or on a credits page for
+your work.
+</string>
+ <key>url</key>
+ <string>http://svn.secondlife.com/svn/linden/trunk/doc/LICENSE-logos.txt</string>
+ </map>
+ <key>boost</key>
+ <map>
+ <key>url</key>
+ <string>http://www.boost.org/LICENSE_1_0.txt</string>
+ </map>
+ <key>bsd</key>
+ <map>
+ <key>url</key>
+ <string>http://www.opensource.org/licenses/bsd-license.php</string>
+ </map>
+ <key>c-ares</key>
+ <map>
+ <key>text</key>
+ <string>http://daniel.haxx.se/projects/c-ares/license.html</string>
+ </map>
+ <key>curl</key>
+ <map>
+ <key>url</key>
+ <string>http://curl.haxx.se/docs/copyright.html</string>
+ </map>
+ <key>fmod</key>
+ <map>
+ <key>url</key>
+ <string>http://www.fmod.org/ifmodlicense.html</string>
+ </map>
+ <key>freetype</key>
+ <map>
+ <key>url</key>
+ <string>http://freetype.sourceforge.net/FTL.TXT</string>
+ </map>
+ <key>glh_linear</key>
+ <map>
+ <key>text</key>
+ <string>glh - is a platform-indepenedent C++ OpenGL helper library
+
+Copyright (c) 2000 Cass Everitt
+Copyright (c) 2000 NVIDIA Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+Redistributions of source code must retain the above
+copyright notice, this list of conditions and the following
+disclaimer.
+Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following
+disclaimer in the documentation and/or other materials
+provided with the distribution.
+The names of contributors to this software may not be used
+to endorse or promote products derived from this software
+without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+Cass Everitt - cass@r3.nu
+
+</string>
+ </map>
+ <key>glut</key>
+ <map>
+ <key>url</key>
+ <string>http://www.xmission.com/~nate/glut/README-win32.txt</string>
+ </map>
+ <key>gpl</key>
+ <map>
+ <key>url</key>
+ <string>http://www.gnu.org/licenses/gpl.html</string>
+ </map>
+ <key>havok</key>
+ <map>
+ <key>text</key>
+ <string>on file</string>
+ </map>
+ <key>intel</key>
+ <map>
+ <key>text</key>
+ <string>Haven't yet found.
+</string>
+ </map>
+ <key>jpeglib</key>
+ <map>
+ <key>text</key>
+ <string>http://nyctergatis.com/jpeglib/</string>
+ </map>
+ <key>jsoncpp</key>
+ <map>
+ <key>text</key>
+ <string>The json-cpp library and this documentation are in Public Domain. Retrieved from http://jsoncpp.sourceforge.net/ on 2009-09-04.</string>
+ <key>url</key>
+ <string>http://jsoncpp.sourceforge.net</string>
+ </map>
+ <key>kdu</key>
+ <map>
+ <key>text</key>
+ <string>jpeg2000 license #00024 (on file)</string>
+ </map>
+ <key>lgpl</key>
+ <map>
+ <key>url</key>
+ <string>http://www.gnu.org/copyleft/lgpl.html</string>
+ </map>
+ <key>libpng</key>
+ <map>
+ <key>text</key>
+ <string>http://www.libpng.org/pub/png/src/libpng-LICENSE.txt</string>
+ </map>
+ <key>linden</key>
+ <map>
+ <key>text</key>
+ <string>Using this license for Linden Lab owned library files</string>
+ </map>
+ <key>mesa</key>
+ <map>
+ <key>url</key>
+ <string>http://www.mesa3d.org/license.html</string>
+ </map>
+ <key>mit</key>
+ <map>
+ <key>text</key>
+ <string>http://www.jclark.com/xml/copying.txt</string>
+ </map>
+ <key>ogg-vorbis</key>
+ <map>
+ <key>url</key>
+ <string>http://www.xiph.org/licenses/bsd/</string>
+ </map>
+ <key>openSSL</key>
+ <map>
+ <key>url</key>
+ <string>http://www.openssl.org/source/license.html</string>
+ </map>
+ <key>openjpeg</key>
+ <map>
+ <key>url</key>
+ <string>http://www.openjpeg.org/BSDlicense.txt</string>
+ </map>
+ <key>quicktime</key>
+ <map>
+ <key>text</key>
+ <string>ENGLISH
+
+Apple Computer, Inc.
+QuickTime 7 Software Developer Kit (SDK)
+Software License Agreement
+
+PLEASE READ THIS SOFTWARE LICENSE AGREEMENT ("LICENSE") BEFORE USING THE SOFTWARE. BY USING THE SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS LICENSE. IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY, SIGNIFY YOUR AGREEMENT TO BE BOUND BY THE TERMS OF THIS LICENSE BY CLICKING THE "AGREE/ACCEPT" BUTTON. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE, RETURN THE APPLE SOFTWARE TO THE PLACE WHERE YOU OBTAINED IT FOR A REFUND OR, IF THE SOFTWARE WAS ACCESSED ELECTRONICALLY, CLICK "DISAGREE/DECLINE".
+
+IMPORTANT NOTE: To the extent this software may be used to reproduce materials, it is licensed to you only for reproduction of materials you are authorized or legally permitted to reproduce.
+
+1. License. Any software, tools, utilities, sample code, documentation, fonts, API?s, header files and other materials accompanying this License, whether on disk, print or electronic documentation, in read only memory, or any other media, (collectively, the "Apple Software") are licensed, not sold, to you by Apple Computer, Inc. ("Apple") for use only under the terms of this License, and Apple reserves all rights not expressly granted to you. The rights granted herein are limited to Apple's and its licensors' intellectual property rights in the Apple Software and do not include any other patents or intellectual property rights. You own the media on which the Apple Software is recorded but Apple and/or Apple's licensor(s) retain ownership of the Apple Software itself. The Apple Software in this package and any copies, modifications and derivative works that this License authorizes you to make are subject to this License.
+
+2. Permitted Uses and Restrictions. You may use the Apple Software to develop application software that is compatible with, and runs only on Mac OS X and/or Windows platforms with QuickTime installed. Except for compiling header files and linking libraries as necessary to build your application software, you have no right to modify, incorporate into or include in combination with your own programs, license or otherwise redistribute any portion of the Apple Software. Your software application may not interfere with the functionality of QuickTime Player or the QuickTime Plug-in, including but not limited to file type or MIME type associations that are registered to QuickTime. You may make only as many internal use copies of the Apple Software as reasonably necessary to use the Apple Software as permitted in this paragraph and distribute such copies only to your employees whose job duties require them to so use the Apple Software. You must reproduce on each copy of the Apple Software or portion thereof, the Apple copyright notice and any other proprietary legends that were on the original copy of the Apple Software. Except as expressly permitted in this License, you may not decompile, reverse engineer, disassemble, modify, rent, lease, loan, sublicense, distribute or create derivative works based upon the Apple Software in whole or part. Your rights under this License will terminate automatically without notice from Apple if you fail to comply with any term(s) of this License. In addition, Apple reserves the right to terminate this License if a new version of Apple's operating system software or the Apple Software is released which is incompatible with the Apple Software.
+
+3. Disclaimer Of Warranty. The Apple Software may be "alpha", "beta", "development", pre-release, untested, and/or not fully tested and may contain errors that could cause failures or loss of data, be incomplete or contain inaccuracies. YOU EXPRESSLY ACKNOWLEDGE AND AGREE THAT USE OF THE APPLE SOFTWARE IS AT YOUR SOLE RISK AND THAT THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY AND EFFORT IS WITH YOU. EXCEPT FOR THE LIMITED WARRANTY ON MEDIA SET FORTH ABOVE AND TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE APPLE SOFTWARE IS PROVIDED "AS IS", WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, AND APPLE AND APPLE'S LICENSORS (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE PURPOSES OF SECTIONS 4 AND 5) HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS WITH RESPECT TO THE APPLE SOFTWARE, EITHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE APPLE SOFTWARE, THAT THE FUNCTIONS CONTAINED IN THE APPLE SOFTWARE WILL MEET YOUR REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SHOULD THE APPLE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES OR LIMITATIONS ON APPLICABLE STATUTORY RIGHTS OF A CONSUMER, SO THE ABOVE EXCLUSION AND LIMITATIONS MAY NOT APPLY TO YOU.
+
+4. Limitation Of Liability. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT SHALL APPLE BE LIABLE FOR PERSONAL INJURY, OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, LOSS OF DATA, BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE THE APPLE SOFTWARE, HOWEVER CAUSED, REGARDLESS OF THE THEORY OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event shall Apple's total liability to you for all damages (other than as may be required by applicable law in cases involving personal injury) exceed the amount of fifty dollars ($50.00). The foregoing limitations will apply even if the above stated remedy fails of its essential purpose.
+
+5. Export Control. You may not use or otherwise export or reexport the Apple Product except as authorized by United States law and the laws of the jurisdiction in which the Apple Product was obtained. In particular, but without limitation, the Apple Product may not be exported or re-exported (a) into any U.S. embargoed countries or (b) to anyone on the U.S. Treasury Department's list of Specially Designated Nationals or the U.S. Department of Commerce Denied Person?s List or Entity List. By using the Apple Product, you represent and warrant that you are not located in any such country or on any such list.
+
+6. Government End Users. The Apple Software and related documentation are "Commercial Items", as that term is defined at 48 C.F.R. ?2.101, consisting of "Commercial Computer Software" and "Commercial Computer Software Documentation", as such terms are used in 48 C.F.R. ?12.212 or 48 C.F.R. ?227.7202, as applicable. Consistent with 48 C.F.R. ?12.212 or 48 C.F.R. ?227.7202-1through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States.
+
+7. Controlling Law and Severability. This License will be governed by and construed in accordance with the laws of the State of California, as applied to agreements entered into and to be performed entirely within California between California residents. This License shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods, the application of which is expressly excluded. If for any reason a court of competent jurisdiction finds any provision, or portion thereof, to be unenforceable, the remainder of this License shall continue in full force and effect.
+
+8. Complete Agreement. This License constitutes the entire agreement between the parties with respect to the use of the Apple Software licensed hereunder and supersedes all prior or contemporaneous understandings regarding such subject matter. No amendment to or modification of this License will be binding unless in writing and signed by Apple. Any translation of this License is done for local requirements and in the event of a dispute between the English and any non-English versions, the English version of this License shall govern.
+
+EA0300
+</string>
+ </map>
+ <key>sleepycat</key>
+ <map>
+ <key>url</key>
+ <string>http://opensource.org/licenses/sleepycat.php</string>
+ </map>
+ <key>smartheap</key>
+ <map>
+ <key>text</key>
+ <string>on file
+</string>
+ </map>
+ <key>things</key>
+ <map>
+ </map>
+ <key>vivox</key>
+ <map>
+ <key>text</key>
+ <string>on file</string>
+ </map>
+ <key>xmlrpc-epi</key>
+ <map>
+ <key>url</key>
+ <string>http://xmlrpc-epi.sourceforge.net/main.php?t=license</string>
+ </map>
+ <key>zlib</key>
+ <map>
+ <key>url</key>
+ <string>http://www.gzip.org/zlib/zlib_license.html</string>
+ </map>
+ </map>
+ </map>
+</llsd>